【问题标题】:Huge Return Data Using Spring RMI (RmiServiceExporter and RmiProxyFactoryBean)使用 Spring RMI(RmiServiceExporter 和 RmiProxyFactoryBean)的巨大返回数据
【发布时间】:2019-07-06 22:49:28
【问题描述】:

似乎“Spring Exporter”除了方法的值之外还返回完整的类路径(文件的 URI):

Wireshark 截图:

在这个示例应用程序中,它大约需要 2KB。但在实际中,它需要十多个 8KB tcp 碎片并导致显着延迟。所以,我正在寻找一种解决方案来防止传递这些额外的数据。

服务器端配置XML:

<beans xmlns="http://www.springframework.org/schema/beans" ...>
    <bean id="calculationBean" class="com.misc.poc.rmi.CalculationImpl"/>
    <bean class="org.springframework.remoting.rmi.RmiServiceExporter">
        <property name="service" ref="calculationBean"/>
        <property name="serviceInterface" value="com.misc.poc.rmi.Calculation"/>
        <property name="serviceName" value="CalculationService"/>
        <property name="servicePort" value="2000"/>
        <property name="registryPort" value="1999"/>
    </bean>
</beans>

客户端配置XML:

<beans xmlns="http://www.springframework.org/schema/beans" ...>
    <bean id="calculationBean" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
        <property name="serviceUrl" value="rmi://192.168.100.94:1999/CalculationService"/>
        <property name="serviceInterface" value="com.misc.poc.rmi.Calculation"/>
        <property name="lookupStubOnStartup" value="false"/>
        <property name="refreshStubOnConnectFailure" value="true"/>
    </bean>
</beans>

一些相关的类:

public interface Calculation {
    int cube(int number);
    Info greeting(String name);
}

public class Info implements Serializable {
    private String title;
    private String desc;

    public String getTitle() { return title; }
    public void setTitle(String title) { this.title = title; }
    public String getDesc() { return desc; }
    public void setDesc(String desc) { this.desc = desc; }
}

public class CalculationImpl implements Calculation {
    @Override
    public int cube(int number){
        return number*number*number;
    }

    @Override
    public Info greeting(String name) {
        Info res = new Info();
        res.setTitle(name);
        res.setDesc("Hello");
        return res;
    }
}

RMI 返回数据:

E   uüg@@7ÐðiøtC}þz8^j¾¾~Q¬íw_`2hå{{R4srcom.misc.poc.rmi.Info^èù¶é¶×LdesctLjava/lang/String;Ltitleq~tÉfile:/home/user/masoud/jobs/huge-marshal/huge-marshal-app/web-server/target/server/WEB-INF/classes/ file:/home/user/masoud/jobs/huge-marshal/huge-marshal-app/web-server/target/server/WEB-INF/lib/spring-security-config-3.2.5.RELEASE.jar file:/home/user/masoud/jobs/huge-marshal/huge-marshal-app/web-server/target/server/WEB-INF/lib/aspectjweaver-1.8.9.jar file:/home/user/masoud/jobs/huge-marshal/huge-marshal-app/web-server/target/server/WEB-INF/lib/spring-web-4.3.10.RELEASE.jar file:/home/user/masoud/jobs/huge-marshal/huge-marshal-app/web-server/target/server/WEB-INF/lib/aopalliance-1.0.jar file:/home/user/masoud/jobs/huge-marshal/huge-marshal-app/web-server/target/server/WEB-INF/lib/common-1.0.jar file:/home/user/masoud/jobs/huge-marshal/huge-marshal-app/web-server/target/server/WEB-INF/lib/commons-logging-1.2.jar file:/home/user/masoud/jobs/huge-marshal/huge-marshal-app/web-server/target/server/WEB-INF/lib/spring-security-taglibs-3.2.5.RELEASE.jar file:/home/user/masoud/jobs/huge-marshal/huge-marshal-app/web-server/target/server/WEB-INF/lib/spring-jdbc-4.3.10.RELEASE.jar file:/home/user/masoud/jobs/huge-marshal/huge-marshal-app/web-server/target/server/WEB-INF/lib/spring-core-4.3.10.RELEASE.jar file:/home/user/masoud/jobs/huge-marshal/huge-marshal-app/web-server/target/server/WEB-INF/lib/spring-security-core-3.2.5.RELEASE.jar file:/home/user/masoud/jobs/huge-marshal/huge-marshal-app/web-server/target/server/WEB-INF/lib/spring-expression-4.3.10.RELEASE.jar file:/home/user/masoud/jobs/huge-marshal/huge-marshal-app/web-server/target/server/WEB-INF/lib/spring-security-acl-3.2.5.RELEASE.jar file:/home/user/masoud/jobs/huge-marshal/huge-marshal-app/web-server/target/server/WEB-INF/lib/spring-context-4.3.10.RELEASE.jar file:/home/user/masoud/jobs/huge-marshal/huge-marshal-app/web-server/target/server/WEB-INF/lib/spring-beans-4.3.10.RELEASE.jar file:/home/user/masoud/jobs/huge-marshal/huge-marshal-app/web-server/target/server/WEB-INF/lib/spring-security-web-3.2.5.RELEASE.jar file:/home/user/masoud/jobs/huge-marshal/huge-marshal-app/web-server/target/server/WEB-INF/lib/spring-tx-4.3.10.RELEASE.jar file:/home/user/masoud/jobs/huge-marshal/huge-marshal-app/web-server/target/server/WEB-INF/lib/spring-aop-4.3.10.RELEASE.jarxptHellotGholi

【问题讨论】:

    标签: java spring rmi wireshark


    【解决方案1】:

    我的理解是,这个 JAR 列表在 RMI 响应中作为“类注释”发送。
    我发现使用https://github.com/NickstaDB/SerializationDumper 提供的SerializationDumper 工具。
    (提示:我必须使用 dd conv=swab &lt;data.orig &gt;data.swapped 交换来自 Wireshark 的转储中的字节顺序,以便将其提供给 SerializationDumper -r。)

          ....
          classAnnotations
            TC_STRING - 0x74
              newHandle 0x00 7e 00 01
              Length - 21685 - 0x54 b5
              Value - file:/app/my-rmi-server-app.jar file:/tmp/cache/repository/org/springframework/boot/spring-boot-starter-web/2.1.4.RELEASE/spring-boot-starter-web-2.1.4.RELEASE.jar file:/tmp/maven/repository/org/springframework/boot/spring-boot-starter/2.1.4.RELEASE/spring-boot-starter-2.1.4.RELEASE.jar ...
    

    我不是 RMI 专家,但我不太清楚 RMI 服务器上的这些路径对显然无法访问这些路径的 RMI 客户端有何用处?!?

    反正这个类注解值是在https://github.com/openjdk/jdk/blob/master/src/java.rmi/share/classes/sun/rmi/server/LoaderHandler.java#L194中生成的。
    该算法利用所谓的类/代码库加载器来确定值必须是什么。
    在我的例子中,我使用Spring Boot Thin Launcher 来打包和运行我的应用程序,所以这可能会对这个算法产生影响。

    我发现总是发送 empty 类注释的方法是用我自己的覆盖默认的RMIClassLoaderSpi

    package my.app;
    
    import java.net.MalformedURLException;
    import java.rmi.server.RMIClassLoader;
    import java.rmi.server.RMIClassLoaderSpi;
    
    public class LeanRMIClassLoaderSpi extends RMIClassLoaderSpi {
        private final RMIClassLoaderSpi delegate;
    
        public LeanRMIClassLoaderSpi() {
            this.delegate = RMIClassLoader.getDefaultProviderInstance();
        }
    
        @Override
        public Class<?> loadClass(String codebase, String name,
                                  ClassLoader defaultLoader) throws MalformedURLException,
                ClassNotFoundException {
            return delegate.loadClass(codebase, name, defaultLoader);
        }
    
        @Override
        public Class<?> loadProxyClass(String codebase, String[] interfaces,
                                       ClassLoader defaultLoader) throws MalformedURLException,
                ClassNotFoundException {
            return delegate.loadProxyClass(codebase, interfaces, defaultLoader);
        }
    
        @Override
        public ClassLoader getClassLoader(String codebase)
                throws MalformedURLException {
            return delegate.getClassLoader(codebase);
        }
    
        @Override
        public String getClassAnnotation(Class<?> cl) {
            return null;
        }
    }
    
    

    Java 系统属性java.rmi.server.RMIClassLoaderSpi 必须设置为my.app.LeanRMIClassLoaderSpihttps://github.com/openjdk/jdk/blob/master/src/java.rmi/share/classes/java/rmi/server/RMIClassLoader.java 中的代码才能获取它。

    而且,瞧,您的 RMI 流量已大大减少 - 在我的情况下,该应用程序仍然可以正常工作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-30
      • 1970-01-01
      相关资源
      最近更新 更多