RMI
(Remote Method Invocation)是從JDK
1.1開始就出現的API功能,它讓客戶端在使用遠端物件所提供的服務時,就如何使用本地物件一樣,然而RMI在使用時必須一連串繁複的手續,像是服務介
面在定義時必須繼承java.rmi.Remote介面、服務Server在實作時必須繼承java.rmi.UnicastRemoteObject類
別、必須使用rmic指令產生stub與skeleton等,設定上手續繁雜。
您可以在Spring中透過org.springframework.remoting.rmi.RmiServiceExporter來簡化使用RMI
的手續,來實際看看例子,了解Spring在RMI上的使用與簡化,首先來看一下RMI伺服端的撰寫,首先定義一個服務物件的介面:
package onlyfun.caterpillar;
public interface ISomeService { public String doSomeService(String some); public int doOtherService(int other); }
服務物件的介面不用繼承java.rmi.Remote介面,而在實作ISomeService時也不用繼承java.rmi.UnicastRemoteObject類別,例如:
package onlyfun.caterpillar;
public class SomeServiceImpl implements ISomeService { public String doSomeService(String some) { return some + " is processed"; } public int doOtherService(int other) { return ++other; } }
這個實作只是個簡單的示範,兩個方法都只是傳回一個已經修改過的值,接下來您只要在Bean定義檔中定義,讓Spring管理、生成Bean實例,如此即可註冊、啟動RMI服務,例如:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING/DTD BEAN/EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans> <bean id="someService" class="onlyfun.caterpillar.SomeServiceImpl"/>
<bean id="serviceExporter" class="org.springframework.remoting. → rmi.RmiServiceExporter"> <property name="service"> <ref bean="someService"/> </property> <property name="serviceName"> <value>SomeService</value> </property> <property name="serviceInterface"> <value>onlyfun.caterpillar.ISomeService</value> </property> </bean> </beans>
很簡單,只要告訴org.springframework.remoting.rmi.RmiServiceExporter服務物件、名稱(注意在
"serviceName"屬性上設定為"SomeService")與要代理的介面,之後Spring讀取完定義檔並生成Bean實例後,RMI服務就
會啟動,來撰寫一個簡單的RMIServer類別,以啟動RMI服務:
package onlyfun.caterpillar;
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import org.springframework.context. support.FileSystemXmlApplicationContext;
public class RMIServer { public static void main(String[] args) throws IOException {
new FileSystemXmlApplicationContext("rmi-server.xml"); System.out.println("啟動 RMI Server.."); System.out.println("請輸入 exit 關閉 Server: "); BufferedReader reader = new BufferedReader( new InputStreamReader(System.in)); while(true) { if(reader.readLine().equals("exit")) { System.exit(0); } } } }
在運行上面的程式之後,RMI服務就會啟動,Spring會自動使用另一個執行緒來執行RMI服務,所以您不用關心執行緒的處理問題,您可以輸入
"exit"直接離開程式,接著來看一下,如何實作一個RMI客戶端以向RMI伺服器要求服務,首先要記得的是,客戶端是依賴於抽象的介面,也就是先前的
ISomeService介面之.class檔也必須在客戶端有一份。
在客戶端需要RMI服務時,只要透過org.springframework.remoting.rmi.RmiProxyFactoryBean,並告
知服務的URL(對應至先前設定的"SomeService"名稱)、代理的介面即可,在撰寫程式時就好像在使用本地端管理的服務一樣,例如Bean定義
檔可以如下撰寫:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING/DTD BEAN/EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans> <bean id="someServiceProxy" class="org.springframework.remoting. → rmi.RmiProxyFactoryBean"> <property name="serviceUrl"> <value>rmi://localhost/SomeService</value> </property> <property name="serviceInterface"> <value>onlyfun.caterpillar.ISomeService</value> </property> </bean> </beans>
注意到"serviceUrl"屬性的設定,它是以"rmi://"開頭,接著指定伺服器位址與服務名稱,來撰寫個簡單的客戶端程式以使用RMI伺服器上的服務:
package onlyfun.caterpillar;
import org.springframework.context.ApplicationContext; import org.springframework.context. support.FileSystemXmlApplicationContext;
public class RMIClient { public static void main(String[] args) { ApplicationContext context = new FileSystemXmlApplicationContext( "rmi-client.xml");
ISomeService service = (ISomeService) context.getBean("someServiceProxy");
String result1 = service.doSomeService("Some request"); System.out.println(result1);
int result2 = service.doOtherService(1); System.out.println(result2); } }
在程式的實作中,您完全不需要處理到有關服務連結的種種細節,代理物件會自動幫您完成這些細節,單從程式來看,您根本不會注意到您正在取得遠端伺服器上的服務。
|