• RMI 使用笔记


    Java 远程方法调用,即 Java RMI( Java Remote Method Invocation ) 。顾名思义,可以使客户机上运行的程序能够调用远程服务器上的对象(方法)。

    下面主要介绍一下使用步骤:

    1.定义远程接口(服务端)

    远程接口定义出可以让客户远程调用的方法。

    此接口必须实现 java.rmi.Remote 接口,来表示其支持远程调用;同时其中声明的所有方法,需要抛出RemoteException异常,因为远程调用的不稳定性(如网络原因等),这样可以让客户端在调用失败时进行相应的处理。

    public interface DemoService extends Remote {
        String sayHello() throws RemoteException;
    }

    2.实现远程接口(服务端)

    远程接口的实现类如果想要被远程访问,可以有如下实现方式:

    继承java.rmi.server.UnicastRemoteObject

    public class DemoServerImpl extends UnicastRemoteObject implements DemoService{
    ​
        public DemoServerImpl() throws RemoteException {
            // 因为 UnicastRemoteObject 构造器抛出 RemoteException
            // 所以此处只能声明一个构造器并抛出对应异常
        }
    ​
        @Override
        public String sayHello() throws RemoteException {
            return "Hello World";
        }
    }

    如果不想继承UnicastRemoteObject类,则需要使用 UnicastRemoteObject类的静态方法exportObject(Remote obj, int port)将对象导出

    其中如果端口设为 0 的话,则表示任何合适的端口都可用来监听客户连接

    public class DemoServerImpl implements DemoService{
    ​
        public DemoServerImpl() throws RemoteException {
            UnicastRemoteObject.exportObject(this, 0);
        }
    ​
        @Override
        public String sayHello() throws RemoteException {
            return "Hello World";
        }
    }

    这两者方法本质上是一样的,在UnicaseRemoteObject类的构造方法中,其实也是调用了exportObject方法

    // UnicaseRemoteObject中的部分源码
    protected UnicastRemoteObject() throws RemoteException
    {
        this(0);
    }
    // if port is zero, an anonymous port is chosen
    protected UnicastRemoteObject(int port) throws RemoteException
    {
        this.port = port;
        exportObject((Remote) this, port);
    }

    3.启动 RMI 注册表

    注册表就像一个电话簿,启动后即可将提供的服务注册到其中,客户可以通过它查询到服务来进行调用

    启动注册表有两种方法,一种是通过命令行rmiregistry来启动,另一种方式是通过LocateRegistry.createRegistry(int port)方法。

    4.注册开启远程服务

    注册服务共有三种方式:

    1. LocateRegistry 类的对象的 rebind() 和 lookup() 来实现绑定注册和查找远程对象的

    2. 利用命名服务 java.rmi.Naming 类的 rebind() 和 lookup() 来实现绑定注册和查找远程对象的

    3. 利用JNDI(Java Naming and Directory Interface,Java命名和目录接口) java.naming.InitialContext 类来 rebind() 和 lookup() 来实现绑定注册和查找远程对象的

    其中第二种方式实际是对第一种方式的简单封装,在内部仍是调用Registry类的bind方法

    // Naming 类的部分源码 (为了节省篇幅,去除了抛出异常部分)
    public static void bind(String name, Remote obj) throws ...
    {
        ParsedNamingURL parsed = parseURL(name);
        Registry registry = getRegistry(parsed);
    ​
        if (obj == null)
            throw new NullPointerException("cannot bind to null");
    ​
        registry.bind(parsed.name, obj);
    }

    服务测试类:

    public class ServerTest {
        public static void main(String[] args) throws Exception{
            String name = "rmi.service.DemoService";
            // 创建服务
            DemoService service = new DemoServerImpl();
            // 创建本机 1099 端口上的 RMI 注册表
            Registry registry1 = LocateRegistry.createRegistry(1099);
          
            /***************** 以下为注册方法一 ************/
            // 将服务绑定到注册表中
            registry1.bind(name, service);
          
            /***************** 以下为注册方法二 ************/
            // Naming.bind(name, service);
          
            /***************** 以下为注册方法三 ************/
            //Context namingContext = new InitialContext();
            //namingContext.bind("rmi:" + name, service); // 此方式 name 需要以 rmi: 开头
          
        }
    }

    客户端测试类:

    public class ClientTest {
        public static void main(String[] args) throws Exception {
            String name = "rmi.service.DemoService";
            /***************** 以下为查找服务方法一 ************/
            // 获取注册表
            Registry registry = LocateRegistry.getRegistry("localhost", 1099);
            // 查找对应的服务
            DemoService service = (DemoService) registry.lookup(name);
          
            /***************** 以下为查找服务方法二 ************/
            // DemoService service = (DemoService) Naming.lookup(name);
          
            /***************** 以下为查找服务方法三 ************/
            //Context namingContext = new InitialContext();
            //DemoService service = (DemoService) namingContext.lookup("rmi:" + name);
          
            // 调用服务
            System.out.println(service.sayHello());
        }
    }

    参考文章:https://segmentfault.com/a/1190000004494341

     

  • 相关阅读:
    JSP XML数据处理
    JSP 连接数据库
    JSP 发送邮件
    IDEA新建maven项目没有webapp目录解决方法
    web项目中idea控制台中文乱码的解决方法
    Spring基础-12-基于xml配置的事务
    Spring基础-11-事务细节
    Spring基础-10-源码分析
    Spring基础-09-事务
    Spring基础-08-jdbcTemplate
  • 原文地址:https://www.cnblogs.com/zawier/p/7043855.html
Copyright © 2020-2023  润新知