MENU

Catalog

JAVA-初识RMI

August 24, 2022 • Read: 447 • Code auditing

简介

RMI (Remote Method Invocation) 模型是一种分布式对象应用,使用 RMI 技术可以使一个 JVM 中的对象,调用另一个 JVM 中的对象方法并获取调用结果。这里的另一个 JVM 可以在同一台计算机也可以是远程计算机。因此,RMI 意味着需要一个 Server 端和一个 Client 端。

Server 端通常会创建一个对象,并使之可以被远程访问。
这个对象被称为远程对象。Server 端需要注册这个对象可以被 Client 远程访问。
Client 端调用可以被远程访问的对象上的方法,Client 端就可以和 Server 端进行通信并相互传递信息。

说到这里,是不是发现使用 RMI 在构建一个分布式应用时十分方便,它和 RPC 一样可以实现分布式应用之间的互相通信,甚至和现在的微服务思想都十分类似。可以先通过这个来了解RPC:https://www.bilibili.com/video/BV1zE41147Zq?from=search&seid=13740626242455157002&vd_source=857de2cc2296579258978d429cb9ebc4

具体的客户端,服务端,注册中心的关系如图:
截屏2022-08-25 17.32.31.png

需要注意的点

客户端:

  1. 存根/桩(Stub):远程对象在客户端上的代理;
  2. 远程引用层(Remote Reference Layer):解析并执行远程引用协议;
  3. 传输层(Transport):发送调用、传递远程方法参数、接收远程方法执行结果。

服务端:

  1. 骨架(Skeleton):读取客户端传递的方法参数,调用服务器方的实际对象方法, 并接收方法执行后的返回值;
  2. 远程引用层(Remote Reference Layer):处理远程引用后向骨架发送远程方法调用;
  3. 传输层(Transport):监听客户端的入站连接,接收并转发调用到远程引用层。

注册表(Registry):

  1. 以URL形式注册远程对象,并向客户端回复对远程对象的引用。

建立RMI的流程如下:

  • 通过分析需求定义远程接口(客户端和服务器端公用的),此接口必须扩展java.rmi.Remote,且远程方法必须声明抛出java.rmi.RemoteException
    异常,或者该异常的超类(Superclass)。
  • 服务器端实现远程接口,为了不手动生成stub需要继承UnicastRemoteObject类,并调用其构造器;
  • 服务器端注册服务并启动;
  • 客户端查询服务并调用远程方法;

现在我们来一个个用实例看看就很好懂了
先定义一个远程接口

package Rmitest;

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

public interface RmiInterface extends Remote {
    public String RmiHello() throws RemoteException ;
    public String sayRmiHello(String Somebody) throws RemoteException;

}

接口必须继承Remote类,每一个定义地方法都要抛出RemoteException异常对象
然后再定义一个类来实现它

package Rmitest;

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

public class RmiObject extends UnicastRemoteObject implements RmiInterface{
    public RmiObject() throws RemoteException{
        super();
    }

    @Override
    public String RmiHello() throws RemoteException {
        return "爱你孤身走暗巷~";
    }

    @Override
    public String sayRmiHello(String Somebody) throws RemoteException {
        return "爱你不跪对模样~";
    }
}

然后远程接口实现类必须继承UnicastRemoteObject类,用于生成 Stub(存根)和 Skeleton(骨架),再使用super来调用父类构造器

然后我们来创建远程对象
截屏2022-08-28 16.41.50.png

最核心的函数就是调用的一个exportObject这个静态函数,然后再经过各种封装,生成一个Stub,最后再发布出去到一个端口上,并记录下来,生成图大概就是这样的原理
B42F56D51163CCE1F76567DB2F5D5686.png

然后就是创建注册中心并绑定远程对象

package Rmitest;

import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.RemoteObject;

public class Rmiserver {
    public static void main(String[] args) throws RemoteException, MalformedURLException {
        RmiInterface rmiObject = new RmiObject();
        Registry registry = LocateRegistry.createRegistry(1099);
        registry.rebind("127.0.0.1:1099/hello",rmiObject);
        System.out.println("服务端创建绑定客户端成功!");
    }
}

然后就是客户端
它先去链接注册中心,得到Stub

package Rmiclient;

import Rmitest.RmiInterface;

import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class Rmiclient {
    public static void main(String[] args) throws RemoteException, NotBoundException {
        Registry registry = LocateRegistry.getRegistry("127.0.0.1", 1099);
        RmiInterface rmiInterface = (RmiInterface)registry.lookup("127.0.0.1:1099/hello");
        System.out.println(rmiInterface.RmiHello());
        System.out.println(rmiInterface.sayRmiHello("hello"));
    }
}

截屏2022-08-28 18.37.38.png

截屏2022-08-28 18.37.55.png

客户端只需要调用 java.rmi.Naming.lookup 函数,通过公开的路径从Rmiserver服务器上拿到对应接口的实现类, 之后通过本地接口即可调用远程对象的方法.

总结

之后的利用学习了cc链再来继续写,就先这样吧
底层原理:https://www.bilibili.com/video/BV1L3411a7ax?spm_id_from=333.999.0.0&vd_source=857de2cc2296579258978d429cb9ebc4

Last Modified: August 28, 2022
Archives Tip
QR Code for this page
Tipping QR Code