- 浏览: 479178 次
- 性别:
- 来自: 大连
文章分类
最新评论
-
龘龘龘:
TrueBrian 写道有个问题,Sample 1中,为了控制 ...
What's New on Java 7 Phaser -
龘龘龘:
楼主总结的不错。
What's New on Java 7 Phaser -
TrueBrian:
有个问题,Sample 1中,为了控制线程的启动时机,博主实际 ...
What's New on Java 7 Phaser -
liguanqun811:
不知道楼主是否对zookeeper实现的分布式锁进行过性能测试 ...
Distributed Lock -
hobitton:
mysql的get lock有版本限制,否则get lock可 ...
Distributed Lock
Spring RMI 不需要输出的接口继承自Remote(这也是Spring一直坚持的原则之一: 业务逻辑不应该同远程逻辑一起设计)。但是这是如何做的呢, 答案是代理。以下是一个简化版的例子程序,用于模拟Spring的实现。
首先是用于发布的接口及实现:
MockProduct.java
public interface MockProduct { String getDescription(); }
MockProductRemote.java
import java.rmi.Remote; import java.rmi.RemoteException; public interface MockProductRemote extends Remote { String getDescription() throws RemoteException; }
MockProductImpl.java
public class MockProductImpl implements MockProduct { public String getDescription() { return "Mock Product"; } }
MockProductRemoteImpl.java
import java.rmi.RemoteException; public class MockProductRemoteImpl implements MockProductRemote { public String getDescription() throws RemoteException { return "Mock Product Remote"; } }
接下来是用于输出RMI服务的类MockRmiServiceExporter.java
import java.rmi.Remote; import java.rmi.RemoteException; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; import java.rmi.server.UnicastRemoteObject; import org.springframework.aop.framework.ProxyFactory; public class MockRmiServiceExporter { // private Object service; private String serviceName; private Class<?> serviceInterface; // private Remote exportedObject; public Object invoke(MockRemoteInvocation invocation, Object wrappedObject) throws RemoteException { return invocation.invoke(wrappedObject); } public void afterPropertiesSet() throws Throwable { Registry reg = getRegistry(); this.exportedObject = getObjectToExport(); UnicastRemoteObject.exportObject(this.exportedObject); reg.rebind(this.serviceName, this.exportedObject); } public Object getService() { return service; } public void setService(Object service) { this.service = service; } public String getServiceName() { return serviceName; } public void setServiceName(String serviceName) { this.serviceName = serviceName; } public Class<?> getServiceInterface() { return serviceInterface; } public void setServiceInterface(Class<?> serviceInterface) { this.serviceInterface = serviceInterface; } private Registry getRegistry() throws RemoteException { try { Registry reg = LocateRegistry.getRegistry(Registry.REGISTRY_PORT); reg.list(); // Test it return reg; } catch (RemoteException ex) { return LocateRegistry.createRegistry(Registry.REGISTRY_PORT); } } private Remote getObjectToExport() { // determine remote object if (getService() instanceof Remote && ((getServiceInterface() == null) || Remote.class.isAssignableFrom(getServiceInterface()))) { // conventional RMI service return (Remote) getService(); } else { // RMI invoker return new MockRmiInvocationWrapper(getProxyForService(), this); } } protected Object getProxyForService() { ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.addInterface(getServiceInterface()); proxyFactory.setTarget(getService()); return proxyFactory.getProxy(); } }
在这个段代码中是用LocateRegistry类的相关方法代替了启动rmiregistry。 在getObjectToExport方法中,如果getService()和getServiceInterface()都没有实现Remote接口,那么实际发布的是MockRmiInvocationWrapper; 相反,如果getService()和getServiceInterface()都实现了Remote接口, 那么实际发布的就是这个Remote接口本身, 这意味着客户端可以不用使用Spring的RMI客户端实现,而是使用传统RMI的方式。
为了保证在不同版本的jdk下都能正确执行,需要手动用rmic为MockRmiInvocationWrapper生成一个stub(但是对于待发布的接口来说,便不再需要stub)。如果使用UnicastRemoteObject.exportObject(this.exportedObject, 0)方法来发布对象,那么连这个stub也可以不必生成。顺便说一下,在Spring的二进制发布包spring-context.jar中有一个RmiInvocationWrapper_Stub.class便是完成类似的功能。
再接下来是MockRmiInvocationWrapper.java的代码, 它实现了Remote接口。
import java.rmi.RemoteException; public class MockRmiInvocationWrapper implements MockRmiInvocationHandler { private Object wrappedObject; private MockRmiServiceExporter rmiExporter; public MockRmiInvocationWrapper(Object wrappedObject, MockRmiServiceExporter rmiExporter) { this.wrappedObject = wrappedObject; this.rmiExporter = rmiExporter; } public Object invoke(MockRemoteInvocation invocation) throws RemoteException { return this.rmiExporter.invoke(invocation, this.wrappedObject); } }
MockRmiInvocationHandler.java
import java.rmi.Remote; import java.rmi.RemoteException; public interface MockRmiInvocationHandler extends Remote { Object invoke(MockRemoteInvocation invocation) throws RemoteException; }
MockRemoteInvocation.java
import java.io.Serializable; import java.lang.reflect.Method; import java.rmi.RemoteException; import org.aopalliance.intercept.MethodInvocation; public class MockRemoteInvocation implements Serializable{ // private static final long serialVersionUID = 1044994565810431680L; // private String methodName; private Class<?>[] parameterTypes; private Object[] arguments; public MockRemoteInvocation(MethodInvocation methodInvocation) { this.methodName = methodInvocation.getMethod().getName(); this.parameterTypes = methodInvocation.getMethod().getParameterTypes(); this.arguments = methodInvocation.getArguments(); } public Object invoke(Object targetObject) throws RemoteException { try { Method method = targetObject.getClass().getMethod(this.methodName, this.parameterTypes); return method.invoke(targetObject, this.arguments); } catch (Exception e) { throw new RemoteException(e.toString()); } } public String getMethodName() { return methodName; } public void setMethodName(String methodName) { this.methodName = methodName; } public Class<?>[] getParameterTypes() { return parameterTypes; } public void setParameterTypes(Class<?>[] parameterTypes) { this.parameterTypes = parameterTypes; } public Object[] getArguments() { return arguments; } public void setArguments(Object[] arguments) { this.arguments = arguments; } }
再接下来是客户端的相关类。在MockRmiProxyFactoryBean中,它使用MethodInterceptor拦截了所有对于导出接口方法的调用并转发给相应的stub。如果这个stub是实现了MockRmiInvocationHandler(比如MockRmiInvocationWrapper), 那么会把所有的调用转发给MockRmiInvocationHandler的invoke方法,同时构造一个MockRemoteInvocation。此后就是通过MockRmiInvocationWrapper_Stub进行远程调用了。
服务器端接收到请求之后,在MockRmiInvocationWrapper类中又把这个请求转发到this.rmiExporter.invoke(invocation, this.wrappedObject)。在MockRmiServiceExporter的invoke方法中,再次转发给MockRemoteInvocation的invoke方法, 最终在MockRemoteInvocation.inovke方法中调用了targetObject上的相关方法。顺便说一下,由于MockRemoteInvocation对象是从客户端通过序列化传递到服务器端的, 而且在这个对象中保存了客户端调用的方法名及参数列表,所以在这个对象中能最终决定应该调用targetObject上的哪个方法。
MockRmiProxyFactoryBean.java
import java.lang.reflect.Method; import java.rmi.Naming; import java.rmi.Remote; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; import org.springframework.aop.framework.ProxyFactory; import org.springframework.beans.factory.FactoryBean; public class MockRmiProxyFactoryBean implements FactoryBean, MethodInterceptor { // private Object serviceProxy; // private String serviceUrl; private Class<?> serviceInterface; public Object getObject() { return serviceProxy; } @SuppressWarnings("unchecked") public Class getObjectType() { return getServiceInterface(); } public boolean isSingleton() { return true; } protected Remote getStub() throws Throwable { Remote stub = Naming.lookup(getServiceUrl()); return stub; } public Object invoke(MethodInvocation invocation) throws Throwable { Remote stub = null; try { stub = getStub(); } catch (Throwable ex) { throw ex; } try { return doInvoke(invocation, stub); } catch (Exception ex) { throw ex; } } protected Object doInvoke(MethodInvocation mi, Remote stub) throws Throwable { if (stub instanceof MockRmiInvocationHandler) { // RMI invoker try { return doInvoke(mi, (MockRmiInvocationHandler)stub); } catch (Exception ex) { throw ex; } } else { // traditional RMI stub try { Method method = mi.getMethod(); if (method.getDeclaringClass().isInstance(stub)) { // directly implemented return method.invoke(stub, mi.getArguments()); } else { // not directly implemented Method stubMethod = stub.getClass().getMethod(method.getName(), method.getParameterTypes()); return stubMethod.invoke(stub, mi.getArguments()); } } catch (Exception ex) { throw ex; } } } protected Object doInvoke(MethodInvocation mi, MockRmiInvocationHandler mrih) throws Throwable { return mrih.invoke(createRemoteInvocation(mi)); } protected MockRemoteInvocation createRemoteInvocation(MethodInvocation mi) throws Throwable { return new MockRemoteInvocation(mi); } public void afterPropertiesSet() { serviceProxy = ProxyFactory.getProxy(getServiceInterface(), this); } public String getServiceUrl() { return serviceUrl; } public void setServiceUrl(String serviceUrl) { this.serviceUrl = serviceUrl; } public Class<?> getServiceInterface() { return serviceInterface; } public void setServiceInterface(Class<?> serviceInterface) { this.serviceInterface = serviceInterface; } }
以上的例子可以看成Spring实现的一个简化版本,其中去掉了复杂的异常处理,一些类的继承关系等。但是保留了基本的控制逻辑,有助于加深理解。
最后是编写两个测试类,检验一下工作成果了。执行前需要生成MockRmiInvocationWrapper的存根类。另外由于MockProductRemote继承了Remote接口,因此不是以MockRmiInvocationWrapper发布的,所以还要生成MockProductRemoteImpl的存根类。
MockRmiServer.java
public class MockRmiServer { public static void main(String args[]) { try { // System.out.println("starting mock server..."); MockProduct mp = new MockProductImpl(); MockRmiServiceExporter rmiExporter1 = new MockRmiServiceExporter(); rmiExporter1.setService(mp); rmiExporter1.setServiceInterface(MockProduct.class); rmiExporter1.setServiceName("mockProduct"); rmiExporter1.afterPropertiesSet(); // rmic MockProductRemoteImpl MockProductRemote mpr = new MockProductRemoteImpl(); MockRmiServiceExporter rmiExporter2 = new MockRmiServiceExporter(); rmiExporter2.setService(mpr); rmiExporter2.setServiceInterface(MockProductRemote.class); rmiExporter2.setServiceName("mockProductRemote"); rmiExporter2.afterPropertiesSet(); System.out.println("done"); } catch (Throwable e) { e.printStackTrace(); } } }
MockRmiClient.java
public class MockRmiClient { public static void main(String args[]) { try { // System.out.println("starting mock client..."); MockRmiProxyFactoryBean factoryBean1 = new MockRmiProxyFactoryBean(); factoryBean1.setServiceUrl("rmi://127.0.0.1:1099/mockProduct"); factoryBean1.setServiceInterface(MockProduct.class); factoryBean1.afterPropertiesSet(); MockProduct mp = (MockProduct)factoryBean1.getObject(); System.out.println("got mock product: " + mp.getDescription()); // MockRmiProxyFactoryBean factoryBean2 = new MockRmiProxyFactoryBean(); factoryBean2.setServiceUrl("rmi://127.0.0.1:1099/mockProductRemote"); factoryBean2.setServiceInterface(MockProductRemote.class); factoryBean2.afterPropertiesSet(); MockProductRemote mpr = (MockProductRemote)factoryBean2.getObject(); System.out.println("got mock product remote: " + mpr.getDescription()); } catch (Throwable e) { e.printStackTrace(); } } }
相关推荐
SpringRMI小例子代码,仅供参考。SpringRMI小例子代码,仅供参考。
闲来无事,做了个Spring RMI的小例子,非常易懂。
为了避免业务逻辑重新开发,顾使用spring rmi,把所有的bean作为rmi服务暴漏出来,在客户端只需要把项目依赖过来就ok,或者把以前的接口导入过来。 参考文档:...
spring RMI 服务(自动把service发布为RMI服务),本例子加入了spring的预处理,可以根据自己的需要把指定位置的bean发布为 RMI 服务。
spring rmi 远程调用服务端和客户端源码,eclipse环境,jdk1.7.
基于spring rmi的一些小改造,在原基础上加入了线程池控制线程数。
spring RMI 简单例子
Spring Rmi的使用,对Spring RMI进行全访问的介绍,并介绍了其中的源代码部分
springRMI接口实现
spring RMI 远程接口调用 包含服务端客户端程序,可完整运行
教您如何创建JAVA RMI ,创建Spring RMI。
spring rmi 客户端 服务器 调用
java项目使用spring rmi所涉及到的包
博文链接:https://callan.iteye.com/blog/162756
spring rmi 多接口服务端配置 调用多接口客户端配置
Spring整合RMI的使用,实现不同项目间方法的远程调用。
NULL 博文链接:https://dolphin-ygj.iteye.com/blog/539379
spring 对 RMI 的封装 一个很精简的例子,用于springRMI的入门学习很好 调试通过咯
NULL 博文链接:https://forgidaved.iteye.com/blog/2142587