211213-JDNI注入:RMI基本知识点介绍

文章目录
  1. 1. RMI科普
  2. 2. 基础体验
    1. 2.1 服务端
    2. 2.2 客户端
    3. 2.3 测试
    4. 3.naming方式
  • 一灰灰的联系方式
  • 远程方法调用,现在更多的使用RPC来处理,至于RMI好像没有那么多了,最近闹的火热的log4j2漏洞,又让几个关键词jndi,rmi,ldap频繁出现;对于我这种面向Spring编程的javer而言,这些是啥? 干嘛用的?为啥漏洞这么多?

    接下来简单学习下RMI的基本知识点

    1. RMI科普

    参考:https://www.jianshu.com/p/de85fad05dcb

    Java RMI,即 远程方法调用(Remote Method Invocation),一种用于实现远程过程调用(RPC)(Remote procedure call)的Java API,能直接传输序列化后的Java对象和分布式垃圾收集。它的实现依赖于Java虚拟机(JVM),因此它仅支持从一个JVM到另一个JVM的调用。

    RMI架构图

    可以简单的将RMI理解为jdk原生提供的rpc支持方式

    2. 基础体验

    基于上面的RMI架构图,要体验一下RMI的基本功能,非常简单了

    2.1 服务端

    要提供一个rmi服务端就比较简单了,不需要额外引入依赖,直接使用

    类似于我们常见的rpc框架,先提供一个接口,终点注意它需要继承Remote接口

    1
    2
    3
    4
    5
    import java.rmi.Remote;
    public interface HelloService extends Remote {
    // 方法抛出异常,这个非常重要,不能少
    String hello() throws RemoteException;
    }

    对应的实现类,重点注意继承自UnicastRemoteObject

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    import java.rmi.RemoteException;
    import java.rmi.server.UnicastRemoteObject;
    import java.time.LocalDateTime;

    /**
    * @author yihui
    * @date 21/12/13
    */
    public class HelloServiceImpl extends UnicastRemoteObject implements HelloService {
    protected HelloServiceImpl() throws RemoteException {
    }

    @Override
    public String hello() throws RemoteException {
    return "hello: " + LocalDateTime.now();
    }
    }

    最后就是启动服务,提供一个上面的接口

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public class RmiServer {

    public static void main(String[] args) throws Exception {
    Registry registry = LocateRegistry.createRegistry(8181);
    // 创建一个远程对象
    HelloService hello = new HelloServiceImpl();
    registry.bind("hello", hello);
    System.out.println("服务已启动");
    Thread.currentThread().join();
    }
    }

    2.2 客户端

    客户端访问rmi服务就很简单了,两行代码即可

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class RmiClient {

    public static void main(String[] args) throws Exception{
    Registry registry = LocateRegistry.getRegistry(8181);
    HelloService hello = (HelloService) registry.lookup("hello");
    String response = hello.hello();
    System.out.println(response);
    }
    }

    2.3 测试

    先启动服务端,再启动客户端,可以看到客户端会拿到一个HelloService的实例,可以直接像调用本地方法一下访问这个方法

    IMAGE

    注意上面这个case,客户端拿到实例,访问实例方法,这个逻辑是在哪里执行的呢?(客户端还是服务端?)

    • 服务端执行(可以通过在实现类中添加一行日志,看下这个日志是在服务端输出的还是客户端输出的)

    3.naming方式

    除了上面的这种方式之外,使用Naming方式的也非常普遍,如下

    服务端,新的写法如下

    1
    2
    3
    4
    5
    6
    public static void main(String[] args) throws Exception {
    Registry registry = LocateRegistry.createRegistry(8181);
    Naming.bind("rmi://localhost:8181/hello", hello);
    System.out.println("服务已启动");
    Thread.currentThread().join();
    }

    客户端的写法如下

    1
    2
    3
    4
    5
    6
    public static void main(String[] args) throws Exception {
    String remoteAddr="rmi://localhost:8181/hello";
    HelloService hello = (HelloService) Naming.lookup(remoteAddr);
    String response = hello.hello();
    System.out.println(response);
    }

    这种方式与前面的效果相同,区别在于当有多个服务端时,使用naming的方式,可以指定ip + 端口号来获取对应的服务提供者

    一灰灰的联系方式

    尽信书则不如无书,以上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激

    QrCode

    # JNDI, Java, RMI

    评论

    Your browser is out-of-date!

    Update your browser to view this website correctly. Update my browser now

    ×