转:rmi spring 常见问题解决
http://blog.csdn.net/zhangzeqin0/archive/2011/04/21/6338753.aspx
用 ./shutdown.sh 关闭 rmi 服务器的 tomcat ,然后 ./startup.sh 启动,客户端连接总是会导致如下错误:
org.springframework.remoting.RemoteLookupFailureException: Lookup of RMI stub failed; nested exception is java.rmi.UnmarshalException: error unmarshalling return; nested exception is:
java.io.EOFException
com.ffcs.ieie.communicate.ieiemp.IeiempException: org.springframework.remoting.RemoteLookupFailureException: Lookup of RMI st
ub failed; nested exception is java.rmi.UnmarshalException: error unmarshalling return; nested exception is:
java.io.EOFException
RMI 问题 1 分析:
The cause of the problem is the fact that Spring creates an RMIRegistry with the classloader of the server webapp. Then, when restarting the server, the RMIRegistry is not shut down. After the restart the Registry keeps its references to the old Stubs which do not exist anymore.
There are two solutions:
1) Start the rmiregistry in a seperate process without the classpath of the server app.
2) (better approach) Let spring start the RMIRegistry throu RmiRegistryFactoryBean, which shuts it down correctly.
参考: http://forum.springframework.org/showthread.php?t=33073
RMI 问题 1 解决:
将服务器中的 spring 配置代码,如下:
< bean id = "incomingService" class = "com.ffcs.ieiemp.ieie.rmi.IncomingService" />
< bean id = "rmiService" class = "org.springframework.remoting.rmi.RmiServiceExporter" >
< property name = "serviceName" value = "IncomingService" />
< property name = "service" ref = "incomingService" />
< property name = "serviceInterface" value = "com.ffcs.ieiemp.ieie.rmi.Incoming" />
< property name = "registryPort" value = "1099" />
</ bean >
替换为:
<bean id="registry" value="1099"/>
</bean>
< bean id = "incomingService" class = "com.ffcs.ieiemp.ieie.rmi.IncomingService" />
< bean id = "rmiService" class = "org.springframework.remoting.rmi.RmiServiceExporter" >
< property name = "serviceName" value = "IncomingService" />
< property name = "service" ref = "incomingService" />
< property name = "serviceInterface" value = "com.ffcs.ieiemp.ieie.rmi.Incoming" />
<!-- <property name="registryPort" value="1099"/> -->
<property name="registry" ref="registry"/>
</ bean >
RMI 问题 2 背景:
RMI 服务器重启,总是会出现客户端连接拒绝的问题。
RMI 问题 2 分析:
服务器重启会影响到客户端?说明客户端有保存着重启之前的服务器连接相关记录。经研究发现,客户端 Stub 有缓存,所以只要刷新缓存即可解决问题。参考: http://forum.springsource.org/showthread.php?t=61575
RMI 问题 2 解决:
在客户端连接代码中增加红色标识的代码:
RmiProxyFactoryBean factory= new RmiProxyFactoryBean();
factory.setServiceInterface(Incoming. class );
factory.setServiceUrl(url);
// XXX vincan: 解决重启 rmi 的服务器后会出现拒绝连接或找不到服务对象的错误
factory.setLookupStubOnStartup(false );
factory.setRefreshStubOnConnectFailure(true );
factory.afterPropertiesSet();
Incoming service=(Incoming)factory.getObject();
因为RMI stub被连接到特定的端点,不仅仅是为每个调用打开一个给定的目标地址的连接,所以如果重新启动RMI端点主机的服务器,那么就需要重新注册这些stub,并且客户端需要再次查询它们。
虽然目标服务的重新注册在重新启动时通常会自动发生,不过此时客户端保持的stub将会变的陈旧,且客户端不会注意这些,除非他们再次尝试调用stub上的方法,而这也将throw一个连接失败的异常。
为了避免这种情形,Spring的RmiProxyFactoryBean提供了一个refreshStubOnConnectFailure的bean属性,如果调用失败,并且连接异常的话,将它设定为true来强制重新自动查询stub。
<bean id="reportService"
, "192.168.39.11" );
可写在全局监听器里成为全局变量。
2. 在 RMI 服务器上 root 身份登录,输入 Vi /etc/hosts ,在第一行添加 192.168.39.11 ieie
3. 若是用 spring, 则在 RmiServiceExporter 中添加属性 <property name="registryHost" value="192.168.39.11" />
-----------------
补充一下, 经过测试, rmi客户端和 服务端放在两台机器上,当服务端关闭再启动时,客户端再连接时 会报
org.springframework.remoting.RemoteConnectFailureException: Could not connect to remote service [rmi://192.168.18.128:9099/UserMgrAction]; nested exception is java.rmi.ConnectException: Connection refused to host: 192.168.18.128; nested exception is: java.net.ConnectException: Connection refused: connect org.springframework.remoting.rmi.RmiClientInterceptorUtils.convertRmiAccessException(RmiClientInterceptorUtils.java:189) org.springframework.remoting.rmi.RmiClientInterceptor.doInvoke(RmiClientInterceptor.java:347) org.springframework.remoting.rmi.RmiClientInterceptor.invoke(RmiClientInterceptor.java:259) org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202) $Proxy7.getUsers(Unknown Source)
而且杯具的是,再也无法恢复了。
原因: 客户端缓存了服务端存根对象,因此访问的还是旧的对象,必须刷新之。
解决方案:同问题2一样,添加重新连接参数到RmiProxyFactoryBean:
<property name="refreshStubOnConnectFailure">
<value>true</value>
</property>
此时再重复上述步骤,在客户端重新调用时,会看到日志里还是出现了上面的异常,但是接着重新做了连接,页面上看到的是运行正常。