RMI(远程接口调用)
1. RMI的原理:
RMI系统结构,在客户端和服务器端都有几层结构。
方法调用从客户对象经占位程序(Stub)、远程引用层(Remote Reference Layer)和传输层(Transport Layer)向下,传递给主机,然后再次经传 输层,向上穿过远程调用层和骨干网(Skeleton),到达服务器对象。 占位程序扮演着远程服务器对象的代理的角色,使该对象可被客户激活。 远程引用层处理语义、管理单一或多重对象的通信,决定调用是应发往一个服务器还是多个。传输层管理实际的连接,并且追追踪可以接受方法调用的远程对象。服务器端的骨干网完成对服务器对象实际的方法调用,并获取返回值。返回值向下经远程引用层、服务器端的传输层传递回客户端,再向上经传输层和远程调用层返回。最后,占位程序获得返回值。
2. RMI(远程方法调用)的组成
一个正常工作的RMI系统由下面几个部分组成:
•远程服务的接口定义
•远程服务接口的具体实现
•桩(Stub)和框架(Skeleton)文件
•一个运行远程服务的服务器
•一个RMI命名服务,它允许客户端去发现这个远程服务
•类文件的提供者(一个HTTP或者FTP服务器)
•一个需要这个远程服务的客户端程序
技术原理
--------- ----------
| 客户 | |服务器|
---------- ----------
| |
------------- ----------
-------------- -----------
| |
------------------------------------
| 远 程 引 用 层 |
------------------------------------
| |
------------------------------------
| 传 输 层 |
------------------------------------
方法调用从客户对象经占位程序(Stub)、远程引用层(Remote Reference Layer)和传输层(Transport Layer)向下,传递给主机,然后再次经传 输层,向上穿过远程调用层和骨干网(Skeleton),到达服务器对象。 占位程序扮演着远程服务器对象的代理的角色,使该对象可被客户激活。 远程引用层处理语义、管理单一或多重对象的通信,决定调用是应发往一个服务器还是多个。传输层管理实际的连接,并且追追踪可以接受方法调用的远程对象。服务器端的骨干网完成对服务器对象实际的方法调用,并获取返回值。返回值向下经远程引用层、服务器端的传输层传递回客户端,再向上经传输层和远程调用层返回。最后,占位程序获得返回值。
要完成以上步骤需要有以下几个步骤:
1、生成一个远程接口
4、编写服务器程序
5、编写客户程序
6、注册远程对象
7、启动远程对象
一、远程接口:
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface Ihello extends Remote{
public String sayHello(String name) throws RemoteException ;
public String hello() throws RemoteException;
}
实现类:
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import com.wa.spring.rmi.dao.Ihello;
public class HelloImpl extends UnicastRemoteObject implements Ihello {
public HelloImpl() throws RemoteException {
super();
}
public String sayHello(String name) throws RemoteException {
return "hello, welcome "+name;
}
public String hello() throws RemoteException {
return "good rmi";
}
}
方法要抛出RemoteException否则出现以下异常:
二、实现远程对象创建服务端程序:
import java.net.MalformedURLException;
import java.rmi.AlreadyBoundException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import com.wa.spring.rmi.dao.Ihello;
import com.wa.spring.rmi.dao.impl.HelloImpl;
/**
*
* @author Administrator
* 创建RMI注册表,启动RMI服务,并将远程对象注册到RMI注册表中。
*/
public class HelloServer {
public static void main(String[] args) {
try {
//创建一个远程对象
Ihello hello = new HelloImpl();
// //本地主机上的远程对象注册表Registry的实例,并指定端口为8888,
//这一步必不可少(Java默认端口是1099),必不可缺的一步,缺少注册表创建,则无法绑定对象到远程注册表上
LocateRegistry.createRegistry(8888);
//把远程对象注册到RMI注册服务器上,并命名为Hello
//绑定的URL标准格式为:rmi://host:port/name(其中协议名可以省略,下面两种写法都是正确的)
Naming.bind("rmi://localhost:8888/Hello",hello);
// Naming.bind("//localhost:8888/RHello",rhello);
System.out.println("====>>>url绑定成功");
} catch (RemoteException e) {
System.out.println("创建远程对象发生异常!");
e.printStackTrace();
} catch (MalformedURLException e) {
System.out.println("url异常");
e.printStackTrace();
} catch (AlreadyBoundException e) {
System.out.println("重复绑定异常");
e.printStackTrace();
}
}
}
三、创建客户端程序:
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import com.wa.spring.rmi.dao.Ihello;
/**
* 在客户端调用远程对象上的远程方法,并返回结果。
* @author Administrator
*
*/
public class HelloClient {
public static void main(String[] args) {
try {
//调用注册的服务
Ihello hello = (Ihello) Naming.lookup("rmi://localhost:8888/Hello");
System.out.println(hello.hello());
System.out.println(hello.sayHello("纳兰容若"));
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (RemoteException e) {
e.printStackTrace();
} catch (NotBoundException e) {
e.printStackTrace();
}
}
}
分别运行服务端和客户端可看到输出信息!
参考资料:
http://baike.baidu.com/view/99017.htm?fr=aladdin
http://www.ibm.com/developerworks/cn/java/j-rmiframe/