跳转至
#java  #java安全  #反序列化 
本文阅读量 

RMI篇1#

RMI全称是Remote Method Invocation,远程⽅方法调用。从这个名字就可以看出,他的目标和RPC其实是类似的,是让某个Java虚拟机上的对象调用另一个Java虚拟机中对象上的方法,只不过RMI是Java独有的一种机制。

一个简单的示例如下

远程调用的方法需要
- 一个继承了java.rmi.Remote的接口
- 一个实现了该接口并继承了UnicastRemoteObject的类

package top.longlone;

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface IRemoteHelloWorld extends Remote {
    public String hello() throws RemoteException;
}

package top.longlone;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

public class RemoteHelloWorld extends UnicastRemoteObject implements IRemoteHelloWorld {
    protected RemoteHelloWorld() throws RemoteException {
        super();
    }

    @Override
    public String hello() throws RemoteException {
        System.out.println("call");
        return "hello world";
    }
}

RMIServer需要创建Registry,并将上面的类实例化后绑定到一个地址。

package top.longlone;

import java.rmi.Naming;
import java.rmi.registry.LocateRegistry;

public class RMIServer {
    private void start() throws Exception {
        RemoteHelloWorld helloWorld = new RemoteHelloWorld();
        LocateRegistry.createRegistry(1099);
        Naming.bind("rmi://192.168.135.142:1099/Hello", helloWorld);
    }

    public static void main(String[] args) throws Exception {
        new RMIServer().start();
    }
}

RMIClient使用Naming.lookup在Registry中找到HelloWorld的对象,这里也可以看出来接口的重要性: 虽然我们是在远程调用方法,但是我们还是需要实例知道有哪些方法,因此客户端也需要这个接口。

package top.longlone;

import java.rmi.Naming;

public class RMIClient {
    public static void main(String[] args) throws Exception{
        IRemoteHelloWorld helloWorld = (IRemoteHelloWorld) Naming.lookup("rmi://192.168.135.142:1099/Hello");
        String ret = helloWorld.hello();
        System.out.println(ret);
    }
}

结合文章所说的,整个RMI的流程如下:

首先客户端连接Registry,并在其中寻找Name是Hello的对象,这个对应数据流中的Call消息;然后Registry返回一个序列化的数据,这个就是找到的Name=Hello的对象,这个对应数据流中的ReturnData消息;客户端反序列化该对象,发现该对象是一个远程对象,地址在192.168.135.142:33769,于是再与这个地址建立TCP连接。在这个新的连接中,才执行真正远程方法调用,也就是hello()。

RMI Registry就像一个网关,他自己是不会执行远程方法的,但RMI Server可以在上面注册一个Name到对象的绑定关系;RMI Client通过Name向RMI Registry查询,得到这个绑定关系,然后再连接RMI Server;最后,远程方法实际上在RMI Server上调用。

回到页面顶部