1. 程式人生 > >RMI的簡單介紹。

RMI的簡單介紹。

這裡是修真院後端小課堂,每篇分享文從

【背景介紹】【知識剖析】【常見問題】【解決方案】【編碼實戰】【擴充套件思考】【更多討論】【參考文獻】

八個方面深度解析後端知識/技能,本篇分享的是:

【RMI的簡單介紹。】

大家好,我是IT修真院鄭州分院第11期的學員何爽,一枚正直純潔善良的後端程式設計師,今天給大家分享一下,修真院官網java(職業)任務8,深度思考中的知識點——RMI的簡單介紹。

 

 

 

1.背景介紹

 

 

 

什麼是RMI:

 

RMI全稱是Remote Method Invocation-遠端方法呼叫,Java RMI在JDK1.1中實現的,其威力就體現在它強大的開發分散式網路應用的能力上,是純Java的網路分散式應用系統的核心解決方案之一。其實它可以被看作是RPC的Java版本。但是傳統RPC並不能很好地應用於分散式物件系統。而Java RMI 則支援儲存於不同地址空間的程式級物件之間彼此進行通訊,實現遠端物件之間的無縫遠端呼叫。

 

 

 

RMI目前使用Java遠端訊息交換協議JRMP(Java Remote Messaging Protocol)進行通訊。由於JRMP是專為Java物件制定的,Java RMI具有Java的"Write Once,Run Anywhere"的優點,是分散式應用系統的百分之百純Java解決方案。用Java RMI開發的應用系統可以部署在任何支援JRE的平臺上。但由於JRMP是專為Java物件制定的,因此,RMI對於用非Java語言開發的應用系統的支援不足。不能與用非Java語言書寫的物件進行通訊。

 

 

2.知識剖析

 

 

 

Java RMI與RPC的區別:

 

 一:RPC 遠端過程呼叫

 

 RPC(Remote Procedure Call Protocol)遠端過程呼叫協議,通過網路從遠端計算機上請求呼叫某種服務。

 

 一次RPC呼叫的過程大概有10步:

 

  1.執行客戶端呼叫語句,傳送引數

 

  2.呼叫本地系統傳送網路訊息

 

  3.訊息傳送到遠端主機

 

  4.伺服器得到訊息並取得引數 

 

  5.根據呼叫請求以及引數執行遠端過程(服務)

 

  6.執行過程完畢,將結果返回伺服器控制代碼

 

  7.伺服器控制代碼返回結果,呼叫遠端主機的系統網路服務傳送結果

 

  8.訊息傳回本地主機 

 

  9.客戶端控制代碼由本地主機的網路服務接收訊息

 

  10.客戶端接收到呼叫語句返回的結果資料

 

 二:RMI 遠端方法呼叫

 

 RMI:遠端方法呼叫(Remote Method Invocation)。能夠讓在客戶端Java虛擬機器上的物件像呼叫本地物件一樣呼叫服務端java 虛擬機器中的物件上的方法。

 

 

 

RMI遠端呼叫步驟:

 

1,客戶呼叫客戶端輔助物件stub上的方法

 

2,客戶端輔助物件stub打包呼叫資訊(變數,方法名),通過網路傳送給服務端輔助物件skeleton

 

3,服務端輔助物件skeleton將客戶端輔助物件傳送來的資訊解包,找出真正被呼叫的方法以及該方法所在物件

 

4,呼叫真正服務物件上的真正方法,並將結果返回給服務端輔助物件skeleton

 

5,服務端輔助物件將結果打包,傳送給客戶端輔助物件stub

 

6,客戶端輔助物件將返回值解包,返回給呼叫者

 

7,客戶獲得返回值

 

 

 

 三:RPC與RMI的區別

 

 1:方法呼叫方式不同:

 

 RMI中是通過在客戶端的Stub物件作為遠端介面進行遠端方法的呼叫。每個遠端方法都具有方法簽名。如果一個方法在伺服器上執行,但是沒有相匹配的簽名被新增到這個遠端介面(stub)上,那麼這個新方法就不能被RMI客戶方所呼叫。

 

 

 

  RPC中是通過網路服務協議向遠端主機發送請求,請求包含了一個引數集和一個文字值,通常形成“classname.methodname(引數集)”的形式。RPC遠端主機就去搜索與之相匹配的類和方法,找到後就執行方法並把結果編碼,通過網路協議發回。

 

 

 

  2:適用語言範圍不同:

 

   RMI只用於Java;

 

   RPC是網路服務協議,與作業系統和語言無關。

 

 

 

  3:呼叫結果的返回形式不同:

 

    Java是面向物件的,所以RMI的呼叫結果可以是物件型別或者基本資料型別;

 

    RMI的結果統一由外部資料表示 (External Data Representation, XDR) 語言表示,這種語言抽象了位元組序類和資料型別結構之間的差異。

 

 

 

RMI有什麼優點:

 

1、面向物件:

 

RMI可將完整的物件作為引數和返回值進行傳遞,而不僅僅是預定義的資料型別。

 

也就是說,可以將類似Java哈西表這樣的複雜型別作為一個引數進行傳遞。

 

2、可移動屬性:

 

RMI可將屬性從客戶機移動到伺服器,或者從伺服器移動到客戶機。

 

3、設計方式:

 

物件傳遞功能使您可以在分散式計算中充分利用面向物件技術的強大功能,如二層和三層結構系統。

 

如果使用者能夠傳遞屬性,那麼就可以在自己的解決方案中使用面向物件的設計方式。

 

所有面向物件的設計方式無不依靠不同的屬性來發揮功能,如果不能傳遞完整的物件——包括實現和型別

 

——就會失去設計方式上所提供的優點。

 

4、安全性:

 

RMI使用Java內建的安全機制保證下載執行程式時使用者系統的安全。

 

RMI使用專門為保護系統免遭惡意小程式侵害而設計的安全管理程式。

 

5、便於編寫和使用

 

RMI使得Java遠端服務程式和訪問這些服務程式的Java客戶程式的編寫工作變得輕鬆、簡單。

 

遠端介面實際上就是Java介面。

 

 

 

RMI有什麼劣勢:

 

  RMI的侷限性之一是RMI是Java語言的遠端呼叫,兩端的程式語言必須是Java實現,對於不同語言間的通訊可以考慮用Web Service或者公用物件請求代理體系(CORBA)來實現。

 

 

 

    對伺服器的IP地址和埠依賴很緊密,但是在開發的時候不知道將來的伺服器IP和埠如何,但是客戶端程式依賴這個IP和埠。這也是RMI的侷限性之一。這個問題有兩種解決途徑:一是通過DNS來解決,二是通過封裝將IP暴露到程式程式碼之外。

 

 

 

3.常見問題 

 

 

 

1. springRMI指定的兩個埠是什麼?

 

 

2. rmi為什麼要拋RemoteException:

 

 

4.解決方案

 

(1)註冊埠:registryPort   註冊埠是RMI註冊遠端服務的埠。

 

     服務埠:servicePort    RMI的通訊需要的傳送資料的埠。如果沒有設定servicePort,則使用隨機埠。

 

 

(2)由於遠端方法的本質還是網路通訊,只不過隱藏了底層實現,網路通訊是經常會出現異常的,所以介面的所有方法都要丟擲RemoteException來說明此方法是有風險的。

 

 

 

5.編碼實戰

 

 

 

6.擴充套件思考

 

 

Tuscany RMI埠問題:

 

 

RMI之所以使用的範圍受限制主要有兩方面原因,其一:必須要是java,平臺的異構性受到限制;其二:穿越防火牆不方便。這裡主要談談RMI如何通過固定分配埠來穿越防火牆。 

RMI穿越防火牆不方便主要是因為除了RMI服務註冊的埠(預設1099)外,與RMI的通訊還需要另外的埠來傳送資料,而另外的埠是隨機分配的,所以要想RMI的客戶能通過防火牆來與RMI服務通訊,

第一種方法:

需要能讓隨機分配的埠固定下來,具體做法如下:

如果是spring+rmi,可以通過spring bean方式來指定兩個埠,但是tuscany不行,需要自己寫類來完成。 

通過比對spring 的指定埠的原始碼發現

<bean id = "rmiService" class = "org.springframework.remoting.rmi.RmiRegistryFactoryBean" >

在這個類裡

通過這個介面配置伺服器相關配置

在RMIServerSocketFactory裡 發現設定埠的介面,百度發現就是這個東西

繼承它的實現,並重寫

public class SMRMISocket extends RMISocketFactory {

private  static Logger logger = LoggerFactory.getLogger(SMRMISocket.class);

   

   @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 = 8089; //不指定就隨機分配了

    logger.info("port服務端埠號:" + port);

    }

    logger.info("服務端埠號:" + port);

     return new ServerSocket(port);

   }

}

在main裡呼叫:

RMISocketFactory.setSocketFactory(new SMRMISocket());

這樣的話RMI分配的埠就被固定了,防火牆只需要開啟1099和8089埠即可。

第二種方法:

在阿里雲中開放所有的埠,這樣不管rmi傳送資料的是哪個埠都可以通過。

 

7.參考文獻

 

https://www.cnblogs.com/ygj0930/p/6542811.html

https://blog.csdn.net/ajun_studio/article/details/7777167

https://blog.csdn.net/solidwang/article/details/17371973

 

8.更多討論

 

Q1:提問人:王耀其:

 

Tuscany內建容器是什麼?

 

A1:回答人(何爽):

 

 Tuscany內建的容器,並非是Jetty,而是Geronimo,Geronimo擁有管理web容器的能力,包括jetty,tomcat,MQ等等;

 

Q2:提問人:周巨集浩

 

Tuscany-rmi埠固定有什麼限制麼?

 

A2:回答人(何爽):

 

  Tuscany-rmi的埠固定可以隨機固定埠,但注意不要埠衝突,一般10000之後的埠都可以隨便使用。

 

Q3:提問人:周巨集浩

 

 spring-rmi和Tuscany-rmi有什麼區別?

 

A3:回答人(何爽):

 

 沒有什麼太大的區別,它們的實現機制都是一樣的,推薦使用spring-rmi,因為它大部分已經封裝好了,我們用時會比較方便,且Tuscany-rmi畢竟出來的時間已經很久了,切一直沒有更新,現在處於無維護現狀。

 

 

9.鳴謝

 

感謝王耀其,常雷雷,此教程是在他們之前技術分享的基礎上完善而成。

 

10.結束語

 

今天的分享就到這裡啦,歡迎大家點贊、轉發、留言、拍磚~

 

 

PPT連結 視訊連結

更多內容,可以加入IT交流群565734203與大家一起討論交流

這裡是技能樹·IT修真院:https://www.jnshu.com,初學者轉行到網際網路的聚集地