`
whitesock
  • 浏览: 484609 次
  • 性别: Icon_minigender_1
  • 来自: 大连
社区版块
存档分类
最新评论

Spring RMI

阅读更多

    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();
        }
    }
}
8
0
分享到:
评论

相关推荐

    SpringRMI小例子

    在这个"SpringRMI小例子"中,我们将深入探讨如何利用Spring框架来增强RMI的功能,使其更加灵活和易于管理。 首先,我们需要理解Spring框架在RMI中的角色。Spring提供了对RMI的高级抽象,通过其`org.springframework...

    Spring RMI小例子

    Spring RMI(Remote Method Invocation)是Java平台上的远程方法调用技术,结合Spring框架,能够帮助开发者轻松地创建分布式应用程序。在这个"Spring RMI小例子"中,我们将深入理解Spring如何简化RMI的使用,以及...

    spring rmi应用

    Spring RMI整合了RMI机制,提供了一种更加灵活和易于管理的方式,让开发者可以在Spring容器中定义远程服务,并通过Spring的IoC(Inversion of Control)和AOP(Aspect Oriented Programming)特性来增强这些服务。...

    spring RMI 服务(自动把service发布为RMI服务)

    Spring RMI服务是一种在Java平台上实现远程方法调用(Remote Method Invocation, RMI)的技术,它允许分布式系统中的不同组件通过网络进行通信。在Spring框架的支持下,我们可以更方便地将服务发布为RMI服务,使得...

    spring rmi 改造

    在IT行业中,Spring框架是Java开发中的一个基石,它提供了丰富的功能来简化应用程序的构建,包括远程过程调用(Remote Method Invocation,RMI)服务。本文将深入探讨"spring rmi 改造"这一主题,主要关注如何在原有...

    spring rmi使用心得

    为了避免业务逻辑重新开发,顾使用spring rmi,把所有的bean作为rmi服务暴漏出来,在客户端只需要把项目依赖过来就ok,或者把以前的接口导入过来。 参考文档:...

    spring rmi 源码

    Spring RMI(Remote Method Invocation)是Spring框架对Java RMI技术的一种封装,使得在Spring环境中使用RMI变得更加简便。RMI是一种Java平台上的远程对象调用机制,它允许一个Java对象在不同的Java虚拟机之间调用另...

    spring RMI简单例子

    Spring RMI(Remote Method Invocation)是Java平台上的远程方法调用技术,结合Spring框架的特性,使得在分布式系统中调用远程服务变得更加便捷。在这个简单的例子中,我们将深入理解Spring RMI的工作原理以及如何...

    spring rmi 小例子

    6. **源码分析**:在提供的压缩包文件`SpringRMI`中,可能包含了上述所有步骤的代码示例。通过阅读这些源码,你可以深入理解Spring RMI的工作原理,包括服务暴露、注册、代理创建等。 7. **工具使用**:在开发过程...

    Spring Rmi使用文档

    ### Spring RMI 使用详解 #### 一、Spring RMI 概述 Spring RMI 是 Spring 框架中用于支持远程方法调用(Remote Method Invocation)的功能模块。通过 Spring RMI, 开发者能够更加简便地搭建和管理远程服务。传统上...

    spring RMI 实用分享

    Spring RMI(Remote Method Invocation)是Java平台上的远程方法调用技术,允许程序在不同的Java虚拟机(JVM)之间进行通信,实现分布式系统。在本文中,我们将深入探讨Spring框架如何集成RMI,以及如何创建和使用...

    Spring-RMI.rar_spring rmi

    1.2 Spring的RMI支持:Spring通过`org.springframework.remoting.rmi.RmiServiceExporter`和`RmiProxyFactoryBean`简化了RMI的使用。`RmiServiceExporter`用于发布服务,而`RmiProxyFactoryBean`则用于创建RMI服务的...

    springRMI接口实现

    Spring Remote Method Invocation (RMI) 是Spring框架提供的一种远程服务调用机制,它允许你在分布式环境中调用对象的方法,就像是在本地执行一样。这个技术基于Java的RMI系统,但通过Spring的抽象层,简化了配置和...

    java项目使用spring rmi所涉及到的包

    在Java项目中,Spring RMI(Remote Method Invocation)是一种整合远程方法调用功能与Spring框架的方式,它使得在分布式环境中管理对象和服务变得更加便捷。本文将深入探讨Spring RMI涉及的包,以及如何在项目中使用...

    spring RMI 远程接口调用

    Spring RMI(Remote Method Invocation)远程接口调用是Spring框架提供的一个特性,它允许你在分布式环境中调用对象的方法,使得应用程序能够跨越网络边界操作远程对象。这个技术在大型企业级应用中尤其有用,因为它...

    spring rmi 简单应用

    Spring RMI(Remote Method Invocation)简单应用主要涉及的是在Java中使用Spring框架来实现远程方法调用的技术。RMI是Java提供的一种分布式计算能力,它允许一个Java对象调用网络另一端的Java对象的方法,实现了...

    spring rmi 集成

    **Spring RMI 集成详解** 在Java开发中,远程方法调用(Remote Method Invocation,RMI)是一种用于在不同Java虚拟机之间进行对象交互的技术。Spring框架提供了对RMI的支持,使得在Spring应用中集成RMI变得更加简单...

Global site tag (gtag.js) - Google Analytics