RMI

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 伺服端 的撰写,首先定义一个服务物件的介面:

•      ISomeService.java
package onlyfun.caterpillar; public interface ISomeService { 	public String doSomeService(String some); 	public int doOtherService(int other); }

服务物件的介面不用继承 java.rmi.Remote 介面,而在实作 ISomeService 时也不用继承 java.rmi.UnicastRemoteObject 类别,例如:

•      SomeService.java
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 服务,例如:

•      rmi-server.xml
<?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 服务:

•      RMIServer.java
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 定义 档可以如下撰写:

•      rmi-client.xml
<?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 伺服器上的服务

•      RMIClient.java
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); 	} }

在程式的实作中,您完全不需要处理到有关服务连结的种种细节,代理物件会自动帮您完成这些细节,单从程式来看,您根本不会注意到您正在取得远端伺服器上的服务。

你可能感兴趣的:(rmi)