RMI 指的是遠程方法調用 (Remote Method Invocation)
1. RMI的原理:
RMI系統結構,在客戶端和服務器端都有幾層結構。
方法調用從客戶對象經占位程序(Stub)、遠程引用層(Remote Reference Layer)和傳輸層(Transport Layer)向下,傳遞給主機,然后再次經傳 輸層,向上穿過遠程調用層和骨干網(Skeleton),到達服務器對象。 占位程序扮演着遠程服務器對象的代理的角色,使該對象可被客戶激活。 遠程引用層處理語義、管理單一或多重對象的通信,決定調用是應發往一個服務器還是多個。傳輸層管理實際的連接,並且追追蹤可以接受方法調用的遠程對象。服 務器端的骨干網完成對服務器對象實際的方法調用,並獲取返回值。返回值向下經遠程引用層、服務器端的傳輸層傳遞回客戶端,再向上經傳輸層和遠程調用層返 回。最后,占位程序獲得返回值。
2. RMI(遠程方法調用)原理示意圖
3.RMI(遠程方法調用)的優點
從最基本的角度看,RMI是Java的遠程過程調用(RPC)機制。與傳統的RPC系統相比,RMI具有若干優點,因為它是Java面向對象方法的一部分。傳統的RPC系統采用中性語言,所以是最普通的系統--它們不能提供所有可能的目標平台所具有的功能。
RMI以Java為核心,可與采用本機方法與現有系統相連接。這就是說,RMI可采用自然、直接和功能全面的方式為您提供分布式計算技術,而這種技術可幫助您以不斷遞增和無縫的方式為整個系統添加Java功能。
RMI的主要優點如下:
面向對象:RMI可將完整的對象作為參數和返回值進行傳遞,而不僅僅是預定義的數據類型。也就是說,您可以將類似Java哈希表這樣的復雜類型作為一個參數進行傳遞。而在目前的RPC系統中,您只能依靠客戶機將此類對象分解成基本數據類型,然后傳遞這些數據類型,最后在服務器端重新創建哈希表。RMI則不需額外的客戶程序代碼(將對象分解成基本數據類型),直接跨網傳遞對象。
可移動屬性:RMI可將屬性(類實現程序)從客戶機移動到服務器,或者從服務器移到客戶機。這樣就能具備最大的靈活性,因為政策改變時只需要您編寫一個新的Java類,並將其在服務器主機上安裝一次即可。
設計方式:對象傳遞功能使您可以在分布式計算中充分利用面向對象技術的強大功能,如二層和三層結構系統。如果您能夠傳遞屬性,那么您就可以在您的解決方案中使用面向對象的設計方式。所有面向對象的設計方式無不依靠不同的屬性來發揮功能,如果不能傳遞完整的對象--包括實現和類型--就會失去設計方式上所提供的優點。
安 全:RMI使用Java內置的安全機制保證下載執行程序時用戶系統的安全。RMI使用專門為保護系統免遭惡意小應用程序侵害而設計的安全管理程序,可保護您的系統和網絡免遭潛在的惡意下載程序的破壞。在情況嚴重時,服務器可拒絕下載任何執行程序。
便於編寫和使用:RMI使得Java遠程服務程序和訪問這些服務程序的Java客戶程序的編寫工作變得輕松、簡單。遠程接口實際上就是Java接口。服務程序大約用三行指令宣布本身是服務程序,其它方面則與任何其它Java對象類似。這種簡單方法便於快速編寫完整的分布式對象系統的服務程序,並快速地制做軟件的原型和早期版本,以便於進行測試和評估。因為RMI程序編寫簡單,所以維護也簡單。
可連接現有/原有的系統:RMI可通過Java的本機方法接口JNI與現有系統進行進行交互。利用RMI和JNI,您就能用Java語言編寫客戶端程序,還能使用現有的服務器端程序。在使用RMI/JNI與現有服務器連接時,您可以有選擇地用Java重新編寫服務程序的任何部分,並使新的程序充分發揮Java的功能。類似地,RMI可利用JDBC、在不修改使用數據庫的現有非Java源代碼的前提下與現有關系數據庫進行交互。
編寫一次,到處運行:RMI是Java“編寫一次,到處運行 ”方法的一部分。任何基於RMI的系統均可100%地移植到任何Java虛擬機上,RMI/JDBC系統也不例外。如果使用RMI/JNI與現有系統進行交互工作,則采用JNI編寫的代碼可與任何Java虛擬機進行編譯、運行。
分布式垃圾收集:RMI采用其分布式垃圾收集功能收集不再被網絡中任何客戶程序所引用的遠程服務對象。與Java 虛擬機內部的垃圾收集類似,分布式垃圾收集功能允許用戶根據自己的需要定義服務器對象,並且明確這些對象在不再被客戶機引用時會被刪除。
並行計算:RMI采用多線程處理方法,可使您的服務器利用這些Java線程更好地並行處理客戶端的請求。Java分布式計算解決方案:RMI從JDK 1.1開始就是Java平台的核心部分,因此,它存在於任何一台1.1 Java虛擬機中。所有RMI系統均采用相同的公開協議,所以,所有Java 系統均可直接相互對話,而不必事先對協議進行轉換。<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="accountService" class="AccountServiceImpl"></bean> <bean class="org.springframework.remoting.rmi.RmiServiceExporter"> <!-- does not necessarily have to be the same name as the bean to be exported --> <property name="serviceName" value="AccountService"/> <property name="service" ref="accountService"/> <property name="serviceInterface" value="AccountService"/> <!-- defaults to 1099 --> <property name="registryPort" value="1199"/> </bean> <bean class="org.springframework.remoting.jaxws.SimpleJaxWsServiceExporter"> <property name="baseAddress" value="http://localhost:8080/"/> </bean> <bean id="accountServiceEndpoint" class="AccountServiceEndpoint"> <property name="accountService" ref="accountService"/> </bean> </beans>
4.1.2. AccountService 定義遠程服務接口
import java.util.List; public interface AccountService { public void insertAccount(Account account); public List<Account> getAccounts(String name); }
4.1.3. 服務端接口實現
import java.util.List; public class AccountServiceImpl implements AccountService { @Override public void insertAccount(Account account) { System.out.print(account.toString()); } @Override public List<Account> getAccounts(String name) { // TODO Auto-generated method stub return null; } }
4.1.3. 服務層
import javax.jws.WebMethod; import javax.jws.WebService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.context.support.SpringBeanAutowiringSupport; @WebService(serviceName="AccountService") public class AccountServiceEndpoint extends SpringBeanAutowiringSupport { @Autowired private AccountService accountService; public void setAccountService(AccountService accountService) { this.accountService = accountService; } @WebMethod public void insertAccount(Account acc) { accountService.insertAccount(acc); } }
4.2. Client調用遠程服務
4.2.1. beans.xml配置
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean class="SimpleObject" id="simpleObject"> <property name="accountService" ref="accountService"/> </bean> <bean id="accountService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean"> <property name="serviceUrl" value="rmi://HOST:1199/AccountService"/> <property name="serviceInterface" value="AccountService"/> </bean> </beans>
4.2.2. 調用
直接通過像調用本地方法一樣。