经过这几天的rmi包开发,总结了为什么带包的问题
原始rmi的请求过程是这样的:
1.在服务端注册一个实例,并发布到socket上,也就是发布一个实例的stub实例,如NDMC发布一个IUser实例,发布时会做个这样的操作
Remote stub = UnicastRemoteObject.exportObject(
proxy, 0); 这个proxy就是IUser的实例,当调用这个方法时,会生成一个stub实例,也就是客户端需要用的
然后执行下面语句进行发布
registry.getRegist().rebind("IUser",
stub);这样就把stub放到socket中了,客户连接到服务端时会把stub文件下载到客户端(我测试过发现客户端只会下载一次,因此
这里就会出现当服务端重启时会有连不上的问题,解决方案就是当客户端连接时捕获connectionexception异常,然后客户端删除掉stub实例,再一次去服务端取一次)。
2.当客户端取stub实例时,会把stub相关的类的包全部下载到客户端,因此开发人员需要注意的是定义接口时不要把多余的包放到接口中,特别是日志包(现在的NDMC和OSE我
已把异常类重新修改了下,以前异常类中有日志包相关连,现在修改了不关连,用了另一种方式打印,呵呵)。下一次调用后则不会再下载stub了,因此不会再下载lib包路径了。
这是我测试看到的结果,第一次会下载包,以后就不会做这件事了。
客户端获取实例时则使用Object service = Naming.lookup(url); 就可以取到了,非常的简单。
3.在开发rmi包时发现一个问题,也就是GC回收问题,前段时间系统内存目录莫名奇妙丢了,也可能是同这个问题有关,解决方案就是如果你不需要这个对象回收,把它变成静态就行了。
spring的rmi的实现过程是这样的:
1.在服务端注册一个实例,同原始的rmi是一样的,唯一不一样的是它生成了一个统一的stub实例,
RmiInvocationWrapper_Stub 类,spring是把该对象发布到socket上。
2.客户端获取stub时,是获取RmiInvocationWrapper_Stub 实例,然后再用反射调用对应的接口来工作的,因此原始的rmi客户端如果要支持spring调用,只需这样写就行了
if (mi.getRealObject() instanceof RmiInvocationWrapper_Stub)
{
RmiInvocationWrapper_Stub obj = (RmiInvocationWrapper_Stub) mi
.getRealObject();
RemoteInvocation invocation = new RemoteInvocation();
invocation.setMethodName(mi.getMethod().getName());
invocation.setArguments(mi.getArgs());
invocation.setParameterTypes(mi.getMethod().getParameterTypes());
return obj.invoke(invocation);
}
///
rmi为什么带lib包分析:
那为什么spring会带那么多包呢,这个就很好说了,因为
RmiInvocationWrapper_Stub 对象是spring包中的一个类,而且又关联到了很多其它类,因此当客户端获取时会下载很多包
路径的。
还有一个问题就是现在网上讨论的spring rmi设置超时问题,其实很简单的,RMISocketFactory.setSocketFactory(obj
);在客户端调用服务端之前设置这个对象就行了,但要注意了,这个对象只能设置一次,多次会抛已经设置异常的
以上已开发了一个工具包,过些天传到资源池下载,完全兼容spring rmi