1. JDNI注入:RMI基本知识点介绍
约 804 字大约 3 分钟
远程方法调用,现在更多的使用RPC来处理,至于RMI好像没有那么多了,最近闹的火热的log4j2漏洞,又让几个关键词jndi,rmi,ldap频繁出现;对于我这种面向Spring编程的javer而言,这些是啥? 干嘛用的?为啥漏洞这么多?
接下来简单学习下RMI的基本知识点
1. RMI科普
Java RMI,即 远程方法调用(Remote Method Invocation),一种用于实现远程过程调用(RPC)(Remote procedure call)的Java API,能直接传输序列化后的Java对象和分布式垃圾收集。它的实现依赖于Java虚拟机(JVM),因此它仅支持从一个JVM到另一个JVM的调用。
可以简单的将RMI理解为jdk原生提供的rpc支持方式
2. 基础体验
基于上面的RMI架构图,要体验一下RMI的基本功能,非常简单了
2.1 服务端
要提供一个rmi服务端就比较简单了,不需要额外引入依赖,直接使用
类似于我们常见的rpc框架,先提供一个接口,终点注意它需要继承Remote
接口
import java.rmi.Remote;
public interface HelloService extends Remote {
// 方法抛出异常,这个非常重要,不能少
String hello() throws RemoteException;
}
对应的实现类,重点注意继承自UnicastRemoteObject
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();
}
}
最后就是启动服务,提供一个上面的接口
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服务就很简单了,两行代码即可
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的实例,可以直接像调用本地方法一下访问这个方法
注意上面这个case,客户端拿到实例,访问实例方法,这个逻辑是在哪里执行的呢?(客户端还是服务端?)
- 服务端执行(可以通过在实现类中添加一行日志,看下这个日志是在服务端输出的还是客户端输出的)
3.naming方式
除了上面的这种方式之外,使用Naming
方式的也非常普遍,如下
服务端,新的写法如下
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();
}
客户端的写法如下
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 + 端口号来获取对应的服务提供者
Loading...