RMI简例

声明:本案例使用的IDE是Eclipse,客户端程序和服务器程序位于同一个project中。

一、基本原理

RMI是Remote Method Invoke的缩写,是JDK提供的一个完善的、简单易用的远程调用框架,它要求客户端和服务器端都是Java程序。下面简述RMI的基本原理:如下图所示,RMI采用代理来负责客户端和服务器之间socket通信的细节。RMI框架分别为远程对象生成了客户端代理和服务器端代理,位于客户端的代理称为存根(Stub),位于服务器端的代理称为骨架(Skeleton)。

远程对象会在客户端生成存根对象。当客户端调用远程对象的方法时,实际上是调用本地存根的相应方法。然后,存根会把被访问的远程对象名、方法名以及参数编组后发送给服务器,由骨架去调用相应的远程方法并把返回值或异常返回给客户端。

二、基本步骤

一般来说,只要继承java.rmi.server.UnicastRemoteObject类和实现java.rmi.Remote 接口就可以成为远程对象。由于java的单继承,继承了UnicastRemoteObject类之后就不能继承其他的类,这时可以在构造方法中调用exportObect()方法,同样可以将其导为远程对象。实际上,UnicastRemoteObject的构造器也会去调用自身的exportObect()的静态方法。下面是创建一个RMI程序的基本步骤:
(1)创建远程接口,继承java.rmi.Remote接口;
(2)创建远程类,实现远程接口;
(3)创建服务器程序,在rmiregistry注册表中注册远程对象;
(4)创建客户端程序,负责定位远程对象,并且调用远程方法。

*创建远程接口

远程接口中声明了可以被客户端访问的远程方法,远程接口应符合以下条件:
(1)直接或间接继承java.rmi.Remote接口;
(2)接口中的所有方法声明抛出java.rmi.RemoteException异常或父异常。
[java] view plain copy
  1. package main;  
  2.   
  3. import java.rmi.Remote;  
  4. import java.rmi.RemoteException;  
  5. // Inherit the java.rmi.Remote interface  
  6. public interface HelloService extends Remote {  
  7.     // Remote method should throw RemoteException  
  8.     public String service(String data) throws RemoteException;  
  9. }  

三、创建远程类

远程类应符合以下条件:
(1)继承java.rmi.server.UnicastRemoteObject类并实现远程接口;
(2)构造器必须抛出java.rmi.RemoteException异常。
[html] view plain copy
  1. package main;  
  2.   
  3. import java.rmi.RemoteException;  
  4. import java.rmi.server.UnicastRemoteObject;  
  5. // Inherit UnicastRemoteObject and implement HelloService interface  
  6. public class HelloServiceImpl extends UnicastRemoteObject  
  7.         implements HelloService {  
  8.   
  9.     private static final long serialVersionUID = 1L;  
  10.     private String name;  
  11.   
  12.     public HelloServiceImpl(String name) throws RemoteException {  
  13.         super();  
  14.         this.name = name;  
  15.         // UnicastRemoteObject.exportObject(this, 0);  
  16.     }  
  17.   
  18.     @Override  
  19.     public String service(String data) throws RemoteException {  
  20.         return data + name;  
  21.     }  
  22. }  

四、创建服务器程序

在这里要介绍几个方法:
  • bind(String name, Object obj): 注册对象,把对象与服务名绑定。如果该服务名已与其他对象绑定,则会抛出NameAlreadyBoundException异常。
  • rebind(String name, Object obj): 注册对象,把对象与服务名绑定。如果该服务名已与其他对象绑定,不会抛异常,而是将新的对象绑定到该服务名上。
  • lookup(String name): 查找对象,返回与指定名称相同的对象。

服务器端首先要创建注册表实例,然后将远程对象注册到注册表上。服务器程序运行就绪之后,不会立即结束,而是去监控客户端的连接。关于服务名的命名格式,推荐使用“rmi://主机名:端口号/实例名”的方式,这样可以避免在远程对象很多的时候因服务名一致而引发的冲突。默认的端口号1099可以省略。

[html] view plain copy
  1. package main;  
  2.   
  3. import java.rmi.RemoteException;  
  4. import java.rmi.registry.LocateRegistry;  
  5.   
  6. import javax.naming.Context;  
  7. import javax.naming.InitialContext;  
  8. import javax.naming.NamingException;  
  9.   
  10. public class Server {  
  11.   
  12.     public static void main(String[] args) {  
  13.         try {  
  14.             LocateRegistry.createRegistry(1099);  
  15.   
  16.             HelloService service1 = new HelloServiceImpl("service1");  
  17.             Context namingContext = new InitialContext();  
  18.             namingContext.rebind("rmi://localhost:1099/HelloService1",  
  19.                     service1);  
  20.         }  
  21.         catch (RemoteException | NamingException e) {  
  22.             // TODO Auto-generated catch block  
  23.             e.printStackTrace();  
  24.         }  
  25.         System.out.println("Successfully register a remote object.");  
  26.   
  27.     }  
  28. }  

五、创建客户端程序

[html] view plain copy
  1. package main;  
  2.   
  3. import java.rmi.RemoteException;  
  4.   
  5. import javax.naming.Context;  
  6. import javax.naming.InitialContext;  
  7. import javax.naming.NamingException;  
  8.   
  9. public class Client {  
  10.     public static void main(String[] args) {  
  11.         // TODO Auto-generated method stub  
  12.         String url = "rmi://localhost:1099/";  
  13.         try {  
  14.             Context namingContext = new InitialContext();  
  15.             HelloService serv = (HelloService) namingContext.lookup(  
  16.                     url + "HelloService1");  
  17.             String data = "This is RMI Client.";  
  18.             System.out.println(serv.service(data));  
  19.         }  
  20.         catch (NamingException | RemoteException e) {  
  21.             // TODO Auto-generated catch block  
  22.             e.printStackTrace();  
  23.         }  
  24.     }  
  25. }  
客户端先根据服务名查找远程对象,然后才能调用远程方法。因此,此处的服务名必须与在服务器中注册的服务名称一致,否则将无法找到远程对象。

六、运行

在Eclipse中先启动Server,然后启动Client即可。

转自:https://blog.csdn.net/xiaoyaoyulinger/article/details/51452674

阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页