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();}@Overridepublic 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("************ 連接遠程服務端 ***********");// 此處強制轉換時,不能轉換成類 Servicevar 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
總結
以上是生活随笔為你收集整理的Java RMI 入门的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用 GraalVM 将基本的 Java
- 下一篇: 剖析数据库中重要而又常被曲解的概念