- 浏览: 484609 次
- 性别:
- 来自: 大连
文章分类
最新评论
-
龘龘龘:
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小例子"中,我们将深入探讨如何利用Spring框架来增强RMI的功能,使其更加灵活和易于管理。 首先,我们需要理解Spring框架在RMI中的角色。Spring提供了对RMI的高级抽象,通过其`org.springframework...
Spring RMI(Remote Method Invocation)是Java平台上的远程方法调用技术,结合Spring框架,能够帮助开发者轻松地创建分布式应用程序。在这个"Spring RMI小例子"中,我们将深入理解Spring如何简化RMI的使用,以及...
Spring RMI整合了RMI机制,提供了一种更加灵活和易于管理的方式,让开发者可以在Spring容器中定义远程服务,并通过Spring的IoC(Inversion of Control)和AOP(Aspect Oriented Programming)特性来增强这些服务。...
Spring RMI服务是一种在Java平台上实现远程方法调用(Remote Method Invocation, RMI)的技术,它允许分布式系统中的不同组件通过网络进行通信。在Spring框架的支持下,我们可以更方便地将服务发布为RMI服务,使得...
在IT行业中,Spring框架是Java开发中的一个基石,它提供了丰富的功能来简化应用程序的构建,包括远程过程调用(Remote Method Invocation,RMI)服务。本文将深入探讨"spring rmi 改造"这一主题,主要关注如何在原有...
为了避免业务逻辑重新开发,顾使用spring rmi,把所有的bean作为rmi服务暴漏出来,在客户端只需要把项目依赖过来就ok,或者把以前的接口导入过来。 参考文档:...
Spring RMI(Remote Method Invocation)是Spring框架对Java RMI技术的一种封装,使得在Spring环境中使用RMI变得更加简便。RMI是一种Java平台上的远程对象调用机制,它允许一个Java对象在不同的Java虚拟机之间调用另...
Spring RMI(Remote Method Invocation)是Java平台上的远程方法调用技术,结合Spring框架的特性,使得在分布式系统中调用远程服务变得更加便捷。在这个简单的例子中,我们将深入理解Spring RMI的工作原理以及如何...
6. **源码分析**:在提供的压缩包文件`SpringRMI`中,可能包含了上述所有步骤的代码示例。通过阅读这些源码,你可以深入理解Spring RMI的工作原理,包括服务暴露、注册、代理创建等。 7. **工具使用**:在开发过程...
### Spring RMI 使用详解 #### 一、Spring RMI 概述 Spring RMI 是 Spring 框架中用于支持远程方法调用(Remote Method Invocation)的功能模块。通过 Spring RMI, 开发者能够更加简便地搭建和管理远程服务。传统上...
Spring RMI(Remote Method Invocation)是Java平台上的远程方法调用技术,允许程序在不同的Java虚拟机(JVM)之间进行通信,实现分布式系统。在本文中,我们将深入探讨Spring框架如何集成RMI,以及如何创建和使用...
1.2 Spring的RMI支持:Spring通过`org.springframework.remoting.rmi.RmiServiceExporter`和`RmiProxyFactoryBean`简化了RMI的使用。`RmiServiceExporter`用于发布服务,而`RmiProxyFactoryBean`则用于创建RMI服务的...
Spring Remote Method Invocation (RMI) 是Spring框架提供的一种远程服务调用机制,它允许你在分布式环境中调用对象的方法,就像是在本地执行一样。这个技术基于Java的RMI系统,但通过Spring的抽象层,简化了配置和...
在Java项目中,Spring RMI(Remote Method Invocation)是一种整合远程方法调用功能与Spring框架的方式,它使得在分布式环境中管理对象和服务变得更加便捷。本文将深入探讨Spring RMI涉及的包,以及如何在项目中使用...
Spring RMI(Remote Method Invocation)远程接口调用是Spring框架提供的一个特性,它允许你在分布式环境中调用对象的方法,使得应用程序能够跨越网络边界操作远程对象。这个技术在大型企业级应用中尤其有用,因为它...
Spring RMI(Remote Method Invocation)简单应用主要涉及的是在Java中使用Spring框架来实现远程方法调用的技术。RMI是Java提供的一种分布式计算能力,它允许一个Java对象调用网络另一端的Java对象的方法,实现了...
**Spring RMI 集成详解** 在Java开发中,远程方法调用(Remote Method Invocation,RMI)是一种用于在不同Java虚拟机之间进行对象交互的技术。Spring框架提供了对RMI的支持,使得在Spring应用中集成RMI变得更加简单...