RMI 远程方法调用的简单实现(附源码)

473 阅读2分钟

RMI(Remote Method Invocation)

RMI简介

RMI(Remote Method Invocation)是专为Java环境设计的远程方法调用机制,远程服务器实现具体的Java方法并提供接口, 客户端本地仅需根据接口类的定义,提供相应的参数即可调用远程方法。 RMI依赖的通信协议为JRMP(Java Remote Message Protocol ,Java 远程消息交换协议), 该协议为Java定制,要求服务端与客户端都为Java编写。这个协议就像HTTP协议一样, 规定了客户端和服务端通信要满足的规范。在RMI中对象是通过序列化方式进行编码传输的。

image.png

RMI demo

这里以远程调用一个通过用户名查询用户信息(假如一个用户名对应一个唯一用户)为例,实现一个简单的rmi流程。

  1. User对象-->rmi的远程对象 (必须可以被序列化) 远程方法调用,会涉及参数的传递和执行结果的返回。参数或者返回值可以是基本数据类型,当然也有可能是对象的引用。所以这些需要被传输的对象必须可以被序列化,这要求相应的类必须实现 java.io.Serializable 接口,否则会抛出java.io.NotSerializableException
// Serializable接口
public class User implements Serializable {

    private String name;
    private Integer age;

    public User() {
    }

    public User(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + ''' +
                ", age=" + age +
                '}';
    }
}
  1. 方法-->rmi方法 任何可以被远程调用方法的对象必须实现 java.rmi.Remote 接口远程对象的实现类必须继承UnicastRemoteObject类。如果不继承UnicastRemoteObject类,则需要手工初始化远程对象,在远程对象的构造方法的调用UnicastRemoteObject.exportObject()静态方法

接口方法

//remote接口
public interface UserRegistryFacade extends Remote {

    User queryUser(String name) throws RemoteException;

}

服务端实现类

//继承UnicastRemoteObject类
public class UserRegistryFacadeImpl extends UnicastRemoteObject implements UserRegistryFacade {
    public UserRegistryFacadeImpl() throws RemoteException {
        super();
    }

    @Override
    public User queryUser(String name) {
        System.out.println("====收到请求====");
        return new User(name, 30);
    }
}
  1. server端注册
try {
    // 本地主机上的远程对象注册表Registry的实例,默认端口1099
    Registry registry = LocateRegistry.createRegistry(9999);
    // 创建一个远程对象
    UserRegistryFacadeImpl userService = new UserRegistryFacadeImpl();
    // 把远程对象注册到RMI注册服务器上,并命名为queryUser
    registry.rebind("userService", (UserRegistryFacadeImpl) userService);
    System.out.println("======= 启动RMI服务成功! =======");
} catch (RemoteException e) {
    e.printStackTrace();
}
  1. client端调用
try {
    String remoteUrl = "rmi://other:9999/userService";
    UserRegistryFacade userService = (UserRegistryFacade) Naming.lookup(remoteUrl);
    User user = userService.queryUser("张三");
    System.out.println("=======> " + user != null ? user.toString() : "" + " <=======");

} catch (NotBoundException | RemoteException e) {
    e.printStackTrace();
} catch (MalformedURLException e) {
    e.printStackTrace();
}
  1. 真实调用过程

image.png

源码

gitee.com/nine-free/l…