今天在重看Spring in Action,看到远程调用这一章。讲到了Spring简化RMI的开发。说实话,在我的工作中还从来没有编写过RMI的代码,关于RMI也只是当初学习的时候看过一点点,现在早就忘记了。因此又把RMI翻出来看了看。
编写RMI客户-服务器程序包括以下的基本步骤:
1. 定义远程接口
2. 实现远程接口
3. 生成stub 和 skeleton (V1.2不需要skeleton)
4. 启动注册表并注册对象
5. 编写使用远程对象的客户
其中1-4是服务器端要进行的工作,5是客户端要进行的工作。下面是一个很简单的RMI的示例程序:
1. 定义远程接口
import java.rmi.Remote;
public interface HelloInterface extends Remote {
public String sayHello() throws java.rmi.RemoteException;
}
2. 实现远程接口
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.Calendar;
public class HelloServer extends UnicastRemoteObject implements HelloInterface {
public HelloServer() throws RemoteException {
super();
}
@Override
public String sayHello() throws RemoteException {
String greeting = null;
int hourOfDay = Calendar.getInstance().get(Calendar.HOUR_OF_DAY);
if (hourOfDay >= 20){
greeting = "Good evening.";
} else if (hourOfDay >= 12){
greeting = "Good afternoon.";
} else {
greeting = "Good Morning";
}
return greeting;
}
}
3. 生成stub和skeleton
使用Java提供的命令行来生成
rmic -d HelloServer
4. 启动注册表并注册对象
import java.rmi.Naming;
import java.rmi.registry.LocateRegistry;
public class HelloServerRegistor {
public static void main(String[] args){
try{
HelloServer server = new HelloServer();
System.out.println("HelloServer is created: ");
LocateRegistry.createRegistry(1099);
Naming.rebind("/HelloServer", server);
System.out.println("HelloServer is bound.");
} catch (Exception e){
e.printStackTrace();
}
}
}
5. 编写客户端程序
import java.rmi.Naming;
import java.rmi.RMISecurityManager;
import ServerSide.HelloInterface;
public class HelloClient {
public static void main(String[] args){
if (System.getSecurityManager() == null){
System.setSecurityManager(new RMISecurityManager());
}
try{
HelloInterface server = (HelloInterface)Naming.lookup("/HelloServer");
System.out.println(server.sayHello());
} catch (Exception e){
e.printStackTrace();
}
}
}
上面是我们直接使用RMI时需要手动完成的工作,注意因为我的实例代码都是运行在同一台机器上的,在RMI的URL中没有指定主机名称。
下面来看我们使用Spring会简化哪些工作。
从客户端的角度来看:
假设已经有服务器提供了HelloServer服务,我们只需要调用该服务。Spring使用RmiProxyFactoryBean来创建指向RMI服务的代理。
引用
<bean id = "HelloServer" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
<property name="serviceUrl">
<value> /HelloServer</value>
</property>
<property name="serviceInterface">
<value>HelloInterface</value>
</property>
</bean>
要调用HelloServer的程序就可以使用Spring定义的这个HelloServer bean来调用RMI了。
抛开Spring所提倡的IoC等,对于客户端来说,其实没有简化多少东西。另外Spring框架在这里会处理所有的RemoteException并将其封装成RuntimeException抛出,因此在客户端程序中不是必须要写RemoteException的处理代码。
从服务器端的角度来看
1.我们仍然需要定义接口,但是不需要继承Remote接口。
2.当然也需要实现该接口。
3.将实现类在Spring中配置为bean
引用
<bean id="HelloServerImpl" class="HelloServer">
......
</bean>
4.使用Spring的RmiServiceExporter将bean输出成一个RMI服务
引用
<bean class="org.spring.framework.remoting.rmi.RmiServiceExporter">
<property name="service">
<ref bean="HelloServerImpl"/>
</property>
<property name="serviceName">
<value>HelloServer</value>
</property>
<property name="serviceInterface">
<value>HelloInterface</value>
</property>
</bean>
对于服务器端来说,原来的步骤3(生成stup和skeleton)与步骤4(启动注册表并注册RMI服务)没有了,取而代之的是配置了RmiServiceExporter类型的bean。但是从实际的工作量上来看,并没有简化多少。
那么使用Spring进行RMI编程到底简化了什么呢?我的理解是,由于Spring封装了RMI的具体实现,所以简化的实际上是对RMI编程知识的要求。