spring rmi

spring rmi

RMI 能够让在某个Java虚拟机上的对象像调用本地对象一样调用另一个java 虚拟机中的对象上的方法。

使用spring框架IOC 依赖注入,大大简化了rmi的开发,仅仅需要在xml中配置远程服务,然后调用即可

示例:

public interface HelloRMIService {
    int getAdd(int a,int b);
}
public class HelloRMIServiceImpl implements HelloRMIService{
    @Override
    public int getAdd(int a, int b) {
        return  a + b;
    }

}
public class MyRMIClient {
    public static void main(String[] args){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationcontext_RMIClient.xml");
        HelloRMIService service = (HelloRMIService)context.getBean("myClient");
        System.out.println(service.getAdd(5, 4));
    }
}
public class MyRMIServer {
    public static void main(String[] args){
        new ClassPathXmlApplicationContext("applicationcontext_RMIServer.xml");
    }

}

applicationcontext_RMIClient.xml

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans     
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="myClient" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
        <property name="serviceUrl" value="rmi://localhost:1099/helloRMI" />
        <property name="serviceInterface" value="com.zhb.rmi.spring.HelloRMIService" />
    </bean>

</beans>

applicationcontext_RMIServer.xml

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans     
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="helloRMIServiceImpl" class="com.zhb.rmi.spring.HelloRMIServiceImpl" />
    <bean id="myHelloRMI" class="org.springframework.remoting.rmi.RmiServiceExporter">
        <property name="service" ref="helloRMIServiceImpl" />
        <property name="serviceName" value="helloRMI" />
        <property name="serviceInterface" value="com.zhb.rmi.spring.HelloRMIService" />
        <!--  <property name="registryPort" value="9999" /> -->

    </bean>

</beans>

服务定义

服务端服务使用RmiServiceExporter输出和绑定服务

RmiServiceExporter 实现InitializingBean接口
该对象初始化的时候,执行afterPropertiesSet方法。
该类有三个步骤:
1. 获取远程服务注册机registry
2. 获取远程服务对象,使用RmiInvocationWrapper封装远程对象代理
3. 导出远程对象
4. registry绑定远程服务。bind

客户端使用 RmiProxyFactoryBean 得到的是一个具体的服务代理对象。

继承RmiClientInterceptor

public Object invoke(MethodInvocation invocation) throws Throwable {
        Remote stub = getStub();
        try {
            return doInvoke(invocation, stub);
        }
        catch (RemoteConnectFailureException ex) {
            return handleRemoteConnectFailure(invocation, ex);
        }
        catch (RemoteException ex) {
            if (isConnectFailure(ex)) {
                return handleRemoteConnectFailure(invocation, ex);
            }
            else {
                throw ex;
            }
        }
    }

invoke方法
1. 获取stub
2. 调用stub方法
3. stub通过socket调用服务端真正的对象方法

protected Object doInvoke(MethodInvocation methodInvocation, RmiInvocationHandler invocationHandler)
        throws RemoteException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {

        if (AopUtils.isToStringMethod(methodInvocation.getMethod())) {
            return "RMI invoker proxy for service URL [" + getServiceUrl() + "]";
        }

        return invocationHandler.invoke(createRemoteInvocation(methodInvocation));
    }

invocationHandler.invoke(createRemoteInvocation(methodInvocation)); 调用的是服务端注册服务时,获取被封装的远程对象的invoke方法。

底层使用的是socket链接服务端。

The major advantage of RMI, compared to Hessian and Burlap, is serialization.

Hessian/Burlap 是基于HTTP的,使用自己私有的对象序列化机制,能很好地穿越防火墙。

spring rmi java标准的序列化机制,不能穿越防火墙。

spring HttpInvoker

基于http,使用Java 对象序列号机制。

下面我们来看看HttpInvoker实现的流程

服务端实现

服务端核心类 HttpInvokerServiceExporter

afterPropertiesSet方法
得到服务对象的代理对象

handleRequest方法

@Override
    public void handleRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        try {
            RemoteInvocation invocation = readRemoteInvocation(request);
            RemoteInvocationResult result = invokeAndCreateResult(invocation, getProxy());
            writeRemoteInvocationResult(request, response, result);
        }
        catch (ClassNotFoundException ex) {
            throw new NestedServletException("Class not found during deserialization", ex);
        }
    }
  1. 解析客户端调用请求,读取序列化对象
  2. 执行调用
  3. 将结果的序列化对象写入输出流
客户端实现

核心类 HttpInvokerProxyFactoryBean

类似于RmiProxyFactoryBean,但是不同于invoke方法,该bean使用http请求获取服务。

发送http请求核心类 HttpComponentsHttpInvokerRequestExecutor

@Override
    protected RemoteInvocationResult doExecuteRequest(
            HttpInvokerClientConfiguration config, ByteArrayOutputStream baos)
            throws IOException, ClassNotFoundException {

        HttpPost postMethod = createHttpPost(config);
        setRequestBody(config, postMethod, baos);
        try {
            HttpResponse response = executeHttpPost(config, getHttpClient(), postMethod);
            validateResponse(config, response);
            InputStream responseBody = getResponseBody(config, response);
            return readRemoteInvocationResult(responseBody, config.getCodebaseUrl());
        }
        finally {
            postMethod.releaseConnection();
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值