IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> Java RMI 入门 -> 正文阅读

[网络协议]Java RMI 入门

??Java RMI 指 JDK 内置的关于实现远程方法调用(Remote Method Invocation)的 API。这些 API 位于包 java.rmi 中。通过 Java RMI,可以直接在客户端调用服务端的方法,并获得其返回值。Java RMI 是 RPC(Remote procedure call) 技术的 Java 实现,它提供了一种非常便捷的方式在 Java 中实现 RPC。

??使用 RMI 之前,需要知道以下概念:

  • 服务端

  • 服务端的暴露方法

  • 客户端

??RMI 可以让客户端调用位于服务端的暴露方法(暴露方法的具体代码位于服务端),就像是这个暴露方法本来就位于客户端一样。不过要注意的是,虽然位于服务端的暴露方法是由客户端触发调用的,但暴露方法是在服务端运行的,客户端只能为其提供实参,并获得其返回值。

如何通信

??对于服务端,它需要为自己设置一个端口号,接着设置哪个对象对外暴露,并为每个暴露对象设置一个名称。暴露了这个对象,就相当于暴露了这个对象的 public 方法。然后,RMI 会自动为每个暴露对象生成一个唯一的 URL,URL 将根据服务端 IP、端口号、暴露对象名来生成。

??对于客户端,只需要根据这个暴露对象的 URL 就可以直接获得这个对象,然后就可以调用这个对象的 public 方法了。

实战

  1. 编写一个暴露对象接口,这个接口必须继承接口 Remote,而后者是 RMI 提供的接口。因为虽然客户端只需要根据 URL 就可以获得暴露对象,但 Java 的语法要求至少要有一个类型才能接收这个对象。也就是说,所有的暴露对象都必须是一个暴露对象接口的子类,且这个暴露对象接口必须对服务端、客户端都可见。

    因此这个暴露对象接口将提供一系列供客户端远程调用的暴露方法。

    package org.wangpai.demo.rmi.common;
    
    import java.rmi.Remote;
    import java.rmi.RemoteException;
    
    public interface Expose extends Remote {
        Response call(Request request) throws RemoteException;
    }
    
  2. 编写提供给这个暴露方法的实参、返回值。注意:它们必须实现接口 Serializable,因为通信时,RMI 底层借助了对象的序列化、反序列化。

    package org.wangpai.demo.rmi.common;
    
    import java.io.Serializable;
    
    public interface Request extends Serializable {
        Object getData();
    }
    
    package org.wangpai.demo.rmi.common;
    
    import java.io.Serializable;
    
    public interface Response extends Serializable {
        Object getData();
    }
    
  3. 对于服务端的具体暴露对象所属的类,它必须还要将类 UnicastRemoteObject 继承,同时实现上面的暴露对象接口。对于服务端的这个具体暴露类,不必对客户端可见,因此服务端可以对其自由拓展。

    package org.wangpai.demo.rmi.server;
    
    import java.rmi.RemoteException;
    import java.rmi.server.UnicastRemoteObject;
    import org.wangpai.demo.rmi.common.Expose;
    import org.wangpai.demo.rmi.common.Request;
    import org.wangpai.demo.rmi.common.Response;
    
    public class Service extends UnicastRemoteObject implements Expose {
        protected Service() throws RemoteException {
            super();
        }
    
        @Override
        public Response call(Request request) throws RemoteException {
            System.out.println("------ 接收到客户端的数据 -------");
            System.out.println(request.getData());
            System.out.println("---------------------------");
            return () -> "Hello, Client.";
        }
    }
    
  4. 在服务端创建这个暴露类的对象,并注册在 RMI 中。

    package org.wangpai.demo.rmi.server;
    
    import java.rmi.AlreadyBoundException;
    import java.rmi.RemoteException;
    import java.rmi.registry.LocateRegistry;
    import org.wangpai.demo.rmi.common.Protocol;
    
    public class Server {
        public static void start() throws RemoteException, AlreadyBoundException {
            var registry = LocateRegistry.createRegistry(Protocol.SERVER_PORT);
            var service = new Service();
            registry.bind(Protocol.SERVICE_URL, service);
        }
    
        public static void main(String[] args) throws RemoteException, AlreadyBoundException {
            start();
        }
    }
    

    这里,服务端需要与客户端进行一些约定,如服务端端口号、暴露对象的 URL 等。

    package org.wangpai.demo.rmi.common;
    
    public class Protocol {
        public final static int SERVER_PORT = 7777;
    
        public final static String SERVER_BASE_URL = "rmi://127.0.0.1:" + SERVER_PORT + "/";
    
        public final static String SERVICE_URL = "service";
    }
    
  5. 现在可以尝试在客户端进行远程调用了。

    package org.wangpai.demo.rmi.client;
    
    import java.net.MalformedURLException;
    import java.rmi.Naming;
    import java.rmi.NotBoundException;
    import java.rmi.RemoteException;
    import org.wangpai.demo.rmi.common.Expose;
    import org.wangpai.demo.rmi.common.Protocol;
    import org.wangpai.demo.rmi.common.Request;
    
    public class Client {
        public static void remoteCall() throws MalformedURLException, NotBoundException, RemoteException {
            System.out.println("************ 连接远程服务端 ***********");
            // 此处强制转换时,不能转换成类 Service
            var service = (Expose) Naming.lookup(Protocol.SERVER_BASE_URL + Protocol.SERVICE_URL);
            System.out.println("************ 远程服务端连接成功 ***********");
    
            System.out.println("************ 开始远程调用 ***********");
            var response = service.call((Request) () -> "Hello, I'm a client.");
            System.out.println("************** 远程调用结束 ********************");
    
            System.out.println("------ 接收到服务端的数据 -------");
            System.out.println(response.getData());
            System.out.println("---------------------------");
        }
    
        public static void main(String[] args) throws MalformedURLException, NotBoundException, RemoteException {
            remoteCall();
        }
    }
    
  6. 注意:项目运行的时候肯定是服务端先启动,然后客户端才能运行。

  7. 客户端运行效果图:

    在这里插入图片描述

  8. 服务端运行效果图:

    在这里插入图片描述

完整代码

??已上传至 GitCode 中,可免费下载:https://gitcode.net/wangpaiblog/20220202-java_rmi

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2022-02-04 11:22:00  更:2022-02-04 11:23:41 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 10:44:51-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码