RMI简介

RMI(Remote Method Invocation,远程方法调用),用于不同虚拟机之间的通信,允许运行在一个java虚拟机的对象去调用运行在另外一个java虚拟机对象的方法。
JRMP(Java Remote Messaging Protocol)是专为Java制定的远程对象协议,所以,RMI是分布式应用系统的纯Java解决方案。

RMI架构

image.png
客户端:请求服务端的远程对象,并尝试调用远程对象的方法。
服务端:创建一个远程对象,把对象的引用注册到注册表中,提供给客户端使用。
Stub:位于客户端,是远程对象在本地的代理,也就是说虽然我们调用的是本地对象,实际上调用的是远程对象。
Skeleton:位于服务器端,是服务端对象的代理。Stub与之通信。
RRL(Remote Reference Layer,远程引用层):管理客户端对远程对象引用的层
Transport Layer(传输层):连接客户端和服务器。管理现有的连接及设置新的连接。

RMI工作流程

  1. 当客户端调用远程对象时,由Stub将此请求传递给RRL。
  2. 当客户端RRL接收到请求时,它将调用remoteRef对象的invoke()方法,这个方法会将请求传递给服务端的RRL。
  3. 服务器端的RRL将请求传递给Skeleton,Skeleton再调用服务器上对应对象的方法。
  4. 将结果传回客户。

RMI Registry

RMI Registry提供服务注册与服务获取。
服务器创建对象时,会通过bind()reBind()方法向RMI Registry注册对象的信息,这个时候要提供RMI Registry的地址、端口以及对象的路径、对象的引用。
客户端需要调用远程对象时,调用lookup()方法,也是要提供RMI Registry的地址、端口,以及所调用远程对象的路径来获取远程对象信息。
服务端和客户端,提供RMI Registry的地址、端口是要找到对应的RMI Registry。
image.png

简单例子

创建RMI Registry

RMI Registry注册到9999端口中

public class RmiRegistry {
    public static void main(String[] args) throws RemoteException, InterruptedException {
        LocateRegistry.createRegistry(9999);
        CountDownLatch latch=new CountDownLatch(1);
        System.out.println("RmiRegistry已启动");
        latch.await();
    }
}

运行结果:
image.png

服务器注册

GoodsService接口,要继承Remote

public interface GoodsService extends Remote {
    String get(int id) throws RemoteException;
}

GoodsServiceImpl实现类,要继承UnicastRemoteObject

public class GoodsServiceImpl extends UnicastRemoteObject implements GoodsService {

    protected GoodsServiceImpl() throws RemoteException {
        super();
    }

    @Override
    public String get(int id) throws RemoteException{
        return "商品ID:" + id;
    }
}

RmiServer,先定义继承了UnicastRemoteObject的实现类,再通过ip、端口以及路径,把这个对象注册到RMI Registry。

public class RmiServer {
    public static void main(String[] args) throws RemoteException, AlreadyBoundException, MalformedURLException {
        GoodsService goodsService = new GoodsServiceImpl();
        Naming.bind("//127.0.0.1:9999/goodsService",goodsService);
        System.out.println("RmiServer已启动");
    }
}

运行结果:
image.png

客户端调用

RmiClient,通过ip、端口以及路径,找到远程服务对象,并调用相应方法

public class RmiClient {
    public static void main(String[] args) throws RemoteException, NotBoundException, MalformedURLException {
        GoodsService goodsService = (GoodsService)Naming.lookup("//127.0.0.1:9999/goodsService");
        System.out.println(goodsService.get(123));
    }
}

运行结果:
image.png


大军
847 声望183 粉丝

学而不思则罔,思而不学则殆