JDNI注入:RMI基本知識點介紹一

語言: CN / TW / HK

遠端方法呼叫,現在更多的使用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 介面

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的例項,可以直接像呼叫本地方法一下訪問這個方法

IMAGE

注意上面這個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 + 埠號來獲取對應的服務提供者

一灰灰的聯絡方式

盡信書則不如無書,以上內容,純屬一家之言,因個人能力有限,難免有疏漏和錯誤之處,如發現bug或者有更好的建議,歡迎批評指正,不吝感激

個人站點:https://blog.hhui.top 微博地址:  小灰灰Blog [1] QQ:一灰灰/3302797840 微信公眾號: 一灰灰blog

QrCode

References

[1] 小灰灰Blog:  https://weibo.com/p/1005052169825577/home