栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java RMI 入门

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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 方法了。

实战

    编写一个暴露对象接口,这个接口必须继承接口 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;
    }
    

    编写提供给这个暴露方法的实参、返回值。注意:它们必须实现接口 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();
    }
    

    对于服务端的具体暴露对象所属的类,它必须还要将类 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.";
        }
    }
    

    在服务端创建这个暴露类的对象,并注册在 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";
    }
    

    现在可以尝试在客户端进行远程调用了。

    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();
        }
    }
    

    注意:项目运行的时候肯定是服务端先启动,然后客户端才能运行。

    客户端运行效果图:

    服务端运行效果图:

完整代码

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

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/727658.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号