RPC(6):RMI实现RPC

1RMI简介

RMI(Remote Method Invocation) 远程方法调用。

RMI是从JDK1.2推出的功能,它可以实现在一个Java应用中可以像调用本地方法一样调用另一个服务器中Java应用(JVM)中的内容。

RMI 是Java语言的远程调用,无法实现跨语言。

2 执行流程

Registry(注册表)是放置所有服务器对象的命名空间。 每次服务端创建一个对象时,它都会使用bind()或rebind()方法注册该对象。 这些是使用称为绑定名称的唯一名称注册的。

要调用远程对象,客户端需要该对象的引用。即通过服务端绑定的名称从注册表中获取对象(lookup()方法)。

3 API介绍

3.1 Remote

java.rmi.Remote 定义了此接口为远程调用接口。如果接口被外部调用,需要继承此接口。

3.2 RemoteException

java.rmi.RemoteException

继承了Remote接口的接口中,如果方法是允许被远程调用的,需要抛出此异常。

3.3 UnicastRemoteObject

java.rmi.server.UnicastRemoteObject

此类实现了Remote接口和Serializable接口。

自定义接口实现类除了实现自定义接口还需要继承此类。

3.4 LocateRegistry

java.rmi.registry.LocateRegistry

可以通过LocateRegistry在本机上创建Registry,通过特定的端口就可以访问这个Registry。

3.5 Naming

java.rmi.Naming

Naming定义了发布内容可访问RMI名称。也是通过Naming获取到指定的远程方法。

4 代码实现

4.1 创建RMI接口

编写接口文件

复制代码
package com.example.demo;

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

// 定义一个远程服务接口。RMI强制要求,必须是Remote接口的实现。
public interface FirstInterface extends Remote {
    // RMI强制要求,所有的远程服务方法,必须抛出RemoteException。
    String first(String name) throws RemoteException;
}

4.2 创建服务端

引入pom文件

复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>rmi_rpc</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>rmi_rpc_server</artifactId>
    <dependencies>
        <dependency>
            <groupId>org.example</groupId>
            <artifactId>rmi_rpc_api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

</project>

编写远程服务接口

复制代码
package com.example.demo.impl;

import com.example.demo.FirstInterface;

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

// 实现远程服务接口。 所有的远程服务实现,必须是Remote接口直接或间接实现类。
// 如果不会创建基于RMI的服务标准实现,可以继承UnicastRemoteObject类型。
// RMI强制要求,所有的方法必须抛出RemoteException,包括构造方法。
public class FirstRMIImpl extends UnicastRemoteObject implements FirstInterface, Remote {
    public FirstRMIImpl() throws RemoteException {
        super();
    }

    public String first(String name) throws RemoteException {
        System.out.println("客户端请求参数是:" + name);
        return "你好," + name;
    }
}

创建启动类,将服务注册到Registry上

复制代码
package com.example.demo;

import com.example.demo.impl.FirstRMIImpl;

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

// 主方法,创建一个服务实现对象,提供服务,并注册到Registry上。
// RMI的Registry在创建的时候,会自动启动一个子线程,并升级为守护线程(服务线程|精灵线程)。提供持久的服务。
public class MainClass {
    public static void main(String[] args) {
        try {
            System.out.println("服务器启动中...");
            // 创建服务对象
            FirstInterface first = new FirstRMIImpl();
            // 注册到Registry(注册中心)上。
            LocateRegistry.createRegistry(9999);
            // 绑定一个服务到注册中心。提供命名,格式为:rmi://ip:port/别名
            // 如果服务重复,抛出异常。 重复的定义是命名冲突。
            // Naming.bind("rmi://localhost:9999/first", first);
            // 重新绑定一个服务到自注册中心。 和bind的区别是,命名冲突,直接覆盖。
            Naming.rebind("rmi://localhost:9999/first", first);

            System.out.println("服务器启动完毕!");
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

启动服务,结果如下:

4.3 创建客户端

引入pom依赖

复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>rmi_rpc</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>rmi_rpc_client</artifactId>
    <dependencies>
        <dependency>
            <groupId>org.example</groupId>
            <artifactId>rmi_rpc_api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

</project>

编写服务调用RMI的RPC服务

复制代码
package com.example.demo;

import java.rmi.Naming;

// 客户端主方法
public class ClientMainClass {
    public static void main(String[] args) {
        // 代理对象的创建。
        FirstInterface first = null;
        try{
            // 使用lookup找服务。通过名字找服务,并自动创建代理对象。
            // 类型是Object,对象一定是Proxy的子类型,且一定实现了服务接口。
            first = (FirstInterface) Naming.lookup("rmi://localhost:9999/first");

            System.out.println("对象的类型是:" + first.getClass().getName());
            String result = first.first("S106,今天课程讲不完了");
            System.out.println(result);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

启动服务,结果如下:

这时候查看服务端程序,会显示连接申请的服务,效果如下:

相关推荐
EasyDSS1 分钟前
国标GB28181设备管理软件EasyGBS远程视频监控方案助力高效安全运营
网络·人工智能
玩转4G物联网3 分钟前
零基础玩转物联网-串口转以太网模块如何快速实现与TCP服务器通信
服务器·网络·物联网·网络协议·tcp/ip·http·fs100p
派阿喵搞电子21 分钟前
Ubuntu下有关UDP网络通信的指令
linux·服务器·网络
光芒Shine33 分钟前
【物联网-ModBus-ASCII】
物联网·网络协议
搬码临时工1 小时前
外网访问内网服务器常用的三种简单操作步骤方法,本地搭建网址轻松让公网连接
服务器·网络·智能路由器
帽儿山的枪手2 小时前
程序员必掌握的iptables五表五链
linux·网络协议
Fortinet_CHINA2 小时前
引领AI安全新时代 Accelerate 2025北亚巡展·北京站成功举办
网络·安全
dustcell.2 小时前
Cisco Packer Tracer 综合实验
网络
光芒Shine3 小时前
【物联网-ModBus-RTU
物联网·网络协议
量子-Alex4 小时前
【反无人机检测】C2FDrone:基于视觉Transformer网络的无人机间由粗到细检测
网络·transformer·无人机