常用的RPC架構---RMI

常用的RPC架構---RMI

在分散式時代的今天,我們經常使用rpc技術來實現不同機器的系統相互呼叫。原則上來說系統間跨程序的呼叫都屬於RPC範疇。

RPC的原理

RPC也就是遠端過程呼叫,一般用來實現部署在不同機器的系統之間的相互呼叫,使得呼叫方像訪問本地資源一樣透過網路傳輸去訪問遠端系統資源。

在rpc架構種有幾個重要的概念(角色):

Client code:客戶端呼叫方式程式碼,也就是我們經常說的消費方。負責發起rpc呼叫,為呼叫方客戶提供api。

Server code:服務端提供呼叫方式程式碼,簡單的,既然有了呼叫方,那麼就得有服務提供方。也就是生產端,服務端實現具體的業務邏輯。

Serializable/Deserialization:在rpc呼叫過程中,負責對透過網路傳輸的資料進行序列化與反序列化,不同的rpc產品有不同的實現方式。主要分為文字和二進位制兩大類。文字最為常見,就是我們經常使用的xml以及json。二進位制的序列化機制包括java原生的序列化機制,也包括常見的Hessian,protobuf,Thrift,MessagePack等。

Stub proxy:可以看做一個代理物件,遮蔽了rpc呼叫過程中複雜的網路處理邏輯。使得rpc呼叫就像是本地呼叫一樣的程式碼風格。

Transport:rpc底層的通訊傳輸模組,透過Socket在客戶端與服務端之間傳遞請求以及響應資訊

常用的RPC架構---RMI

常見的RPC框架

常見的RPC框架有RMI,WebService,Thrift,gRPC,Http Client等等。今天著重瞭解RMI。

RMI

Java RMI是一種基於Java的遠端方法呼叫技術,是Java實現的一種rpc。它能使部署在不同機器上的Java物件之間進行通訊,方法呼叫

RMI有以下幾個特點:

支援多型性。這是RMI有區別於其他RPC框架的主要優勢之一。

只支援java語言。

使用了java原生的序列化機制。也就是必須實現java。io。Serializable介面。

底層基於BIO實現Socket。

由於BIO機制的原因,導致效能較差,所以在高效能的場景下不建議使用RMI。

RMI簡單入手

1)建立UserService介面:

public interface UserService extends Remote { public void save(String username) throws Exception ; }

2)建立UserServiceImpl實現類

public class UserServiceImpl extends UnicastRemoteObject implements UserService, Serializable { private static final long serialVersionUID = -9206357578911294402L; @Override public void save(String username) throws Exception { System。out。println(“rmi………………username=”+username); }

public UserServiceImpl ()throws Exception{

} }

服務端的實現要繼承UnicastRemoteObject,該類定義了服務呼叫方與服務提供方物件例項,並建立一對一的連線

3)UserServer服務註冊端

public class UserServer { public static void main(String[] args) throws Exception { UserService userService = new UserServiceImpl(); //註冊服務 LocateRegistry。createRegistry(8866); Naming。bind(“rmi://localhost:8866/userService”,userService); System。out。println(“Server code init finish………………。。。。。”); } }

4)UserClient:

public class UserClient { public static void main(String[] args) throws Exception { UserService userService = (UserService) Naming。lookup(“rmi://localhost:8866/userService”); userService。save(“張三”); } }

5)先執行UserServer的main方法,然後再執行UserClient的main方法。控制檯已經列印;

常用的RPC架構---RMI

RMI穿透防火牆

RMI的通訊埠是隨機產生的,因此有可能被防火牆攔截。為了防止被攔截,需要強制RMI指定的通訊介面。一般透過自定義RMISocketFactory類來實現。

public class UserSocketFactory extends RMISocketFactory { @Override public Socket createSocket(String host, int port) throws IOException { return new Socket(host, port); }

@Override public ServerSocket createServerSocket(int port) throws IOException { if(port == 0){ port = 8866; } return new ServerSocket(port); } }

然後在使用的時候注入即可:

public static void main(String[] args) throws Exception { UserService userService = new UserServiceImpl(); //使用UserSocketFactory,指定通訊介面,防止防火牆攔截 RMISocketFactory。setSocketFactory(new UserSocketFactory());

//註冊服務 LocateRegistry。createRegistry(8866); Naming。bind(“rmi://localhost:8866/userService”,userService); System。out。println(“Server code init finish………………。。。。。”); } }

本人水平有限,難免有錯誤或遺漏之處,望大家指正和諒解,提出寶貴意見,願與之交流。