java RMI 技术介绍和实践

        在项目上发现了使用rmi技术,充电一波

RMI 概述

        RMI(Remote Method Invocation)是一种 Java 编程语言中的远程过程调用(RPC)协议,用于在不同的Java虚拟机(JVM)之间进行通信和交互。它允许远程计算机上的Java对象像本地对象一样进行访问和操作,从而使分布式应用程序的开发变得更加容易和方便。

RMI 基本思想

        RMI 基本思想是远程方法调用,即客户端调用某个方法,其本质是将这个方法的调用请求,发送给服务器,由服务器代为执行,且,服务器将执行结果回送客户端。

  • 对于客户端而言,RMI 只要求客户端针对方法本身,产生一种错觉:方法是在本地被调用的;
  • 对于服务器而言,RMI 相当于要处理一个来自客户端的“请求”;这个请求针对某个方法。

RMI 设计分析

客户端功能:

  1. 连接 RMI 服务器;
  2. 远程方法的消费者,从Registry获取远程方法的相关信息并且调用
  3. 等待服务器返回这个方法在服务器端执行的结果。

服务器端功能:

  1. 建立 RMI 服务器;
  2. 侦听客户端连接请求;
  3. 连接 RMI 客户端;
  4. 接受客户端发送过来的要执行的方法名称、实参等信息;找到这个需要代理执行方法,并反射机制执行该方法,并将方法执行的结果回传给客户端,断开与客户端的连接。

Registry:

        提供服务注册与服务获取。即Server端向Registry注册服务,比如地址、端口等一些信息,Client端从Registry获取远程对象的一些信息,如地址、端口等,然后进行远程调用。

工作流程:

  1. 首先,启动RMI Registry服务,启动时可以指定服务监听的端口,也可以使用默认的端口(1099);

  2. 其次,Server端在本地先实例化一个提供服务的实现类,然后通过RMI提供的Naming/Context/Registry等类的bindrebind方法将刚才实例化好的实现类注册到RMI Registry上并对外暴露一个名称;

  3. 最后,Client端通过本地的接口和一个已知的名称(即RMI Registry暴露出的名称),使用RMI提供的Naming/Context/Registry等类的lookup方法从RMI Service那拿到实现类。这样虽然本地没有这个类的实现类,但所有的方法都在接口里了,便可以实现远程调用对象的方法了;

Demo

定义一个接口

package com.cjian.rmi;

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

/**
 * @Author: cjian
 * @Date: 2023/11/8 10:17
 * @Des:
 */
public interface PersonController extends Remote {
    // 注意这里必须抛出RemoteException,否则在查找服务的时候会提示 illegal remote method encountered 异常
    String queryName() throws RemoteException;
}

服务端有上面接口的具体实现,这里实现main方法运行

package com.cjian.rmi;

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

/**
 * @Author: cjian
 * @Date: 2023/11/8 10:17
 * @Des:
 */
public class PersonControllerImpl extends UnicastRemoteObject implements PersonController {

    protected PersonControllerImpl() throws RemoteException {
    }

    @Override
    public String queryName() {
        System.out.println("Receive request");
        return "My name's CJ";
    }

    public static void main(String[] args) {
        try {
            //创建服务端
            PersonController personController = new PersonControllerImpl();
            //注册到8888端口,也注册可以注册到别的机器上。
            LocateRegistry.createRegistry(8888);
            //绑定服务端到指定的地址,这里的localhost对应的上一步注册端口号的机器
            java.rmi.Naming.rebind("rmi://localhost:8888/" + PersonController.class.getName(), personController);
            System.out.println("Ready...");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

启动:

java RMI 技术介绍和实践_第1张图片

客户端调用

package com.cjian.rmi;

import java.rmi.Naming;

/**
 * @Author: cjian
 * @Date: 2023/11/8 10:21
 * @Des:
 */
public class ClientTest {
    public static void main(String[] args) {
        try {
            //客户端去查找指定的服务
            PersonController personController = (PersonController) Naming.lookup("rmi://localhost:8888/" + PersonController.class.getName());
            //打印的结果应该是 My name's CJ
            System.out.println(personController.queryName());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

测试结果:

java RMI 技术介绍和实践_第2张图片

java RMI 技术介绍和实践_第3张图片

另一种写法:

package com.cjian.rmi.custom;

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

/**
 * @Author: cjian
 * @Date: 2023/11/8 10:17
 * @Des:
 */
public interface PersonController2 extends Remote {
    // 注意这里必须抛出RemoteException,否则在查找服务的时候会提示 illegal remote method encountered 异常
    String queryName() throws RemoteException;
}
package com.cjian.rmi.custom;

import com.cjian.rmi.PersonController;

import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;

/**
 * @Author: cjian
 * @Date: 2023/11/8 10:17
 * @Des:
 */
public class PersonControllerImpl2 implements PersonController {

    @Override
    public String queryName() {
        System.out.println("Receive request");
        return "My name's CJ";
    }

    public static void main(String[] args) {
        try {
            //创建服务端
            PersonController personController = new PersonControllerImpl2();
            //注册到8888端口,也注册可以注册到别的机器上。
            UnicastRemoteObject.exportObject(personController, 8080);
            Registry registry = LocateRegistry.createRegistry(8888);
            registry.rebind(PersonController.class.getName(), personController);
            System.out.println("Ready...");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
package com.cjian.rmi.custom;

import com.cjian.rmi.PersonController;

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

/**
 * @Author: cjian
 * @Date: 2023/11/8 10:21
 * @Des:
 */
public class ClientTest2 {
    public static void main(String[] args) {
        try {
            Registry registry = LocateRegistry.getRegistry("localhost", 8888);
            PersonController personController = (PersonController) registry.lookup(PersonController.class.getName());
            System.out.println(personController.queryName());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

效果一样

你可能感兴趣的:(java基础,java-ee)