RMI 入门

来源:互联网 发布:安卓相册软件 编辑:程序博客网 时间:2024/06/06 01:00

 

1、  RMI(Remote Method Invocation)概念

 

RMI是远程方法调用的简称,象其名称暗示的那样,它能够帮助我们查找并执行远程对象的方法。通俗地说,远程调用就象将一个class放在A机器上,然后在B机器中调用这个class的方法。

让某个java虚拟机上的对象调用另一个java虚拟机中的对象和方法。

 

 

 

2、RMI术语

在研究代码之前,我们来看看必须编写哪些代码:

 

·远程对象:Remote 接口用于标识其方法可以从非本地虚拟机上调用的接口。任何远程对象都必须直接或间接实现此接口。只有在“远程接口”(扩展 java.rmi.Remote 的接口)中指定的这些方法才可远程使用。

 

·远程对象实现:这是一个实现远程对象的类。如果实现了远程对象,就能够覆盖该对象中的所有方法,因此,远程对象的实现类将真正包含我们希望导出的方法的代码。

 

·远程服务器:这是一个作为服务器使用的类,它是相对于要访问远程方法的客户端而言的。它存储着绑定的字符串和对象。

 

·远程客户端:这是一个帮助我们访问远程方法提供帮助的类,它也是最终用户。我们将使用查找和调用远程方法的方法在该类中调用远程方法。

 

 

Stub(存根)和Skeleton(骨架)

   Stub和Skeleton是经过rmic命令生成的,我们的程序要通过远程调用,底层一定是套接字的字节传输,要一个对象序列化成为一个字节数组,传输到服务器或者客户端的对端之后,再把该对象反序列化成为对应的对象,这些网络传输的过程要求安全,稳定等等非常麻烦的操作,Stub驻留客户端,承担着代理远程对象的实现者的角色,Skeleton类帮助远程对象与Stub再RMI连接上进行通信。RMI的客户与Stub进行交换,Stub与Skeleton通信,Skeketon负责与服务器进行交互,因此有了Stub和Skeleton之后我们就不需要实现底层通信的细节,我们进行的远程调用,只需要通过接口对方法进行操作即可,使分布式调用实现了位置上的透明,即:远程调用就像本地调用一样。

 

下面这个例子是在网上搜的,觉得挺好的,这里就摘录 了

 

 

 

1. 创建远程接口及声明远程方法(ICal.java)

 

 

/** * 如果想要用 远程对象调用 接口必须要继承Remote或者类必须要实现Remote接口  */public interface ICal extends Remote {//接口定义的方法需要抛出RemoteException异常public int sum(int add1, int add2) throws RemoteException;}

 

 2. 实现远程接口及远程方法(继承UnicastRemoteObject)(ICalImpl.java)

 

UnicastRemoteObject 类用于导出带 JRMP 的远程对象和获得与该远程对象通信的 stub,即使远程对象具有相应的存根,并使它能够远程客户的方法调用请求。该类实现了Serializable, Remote接口,可以实现底层的序列化对象网络传输的需求。

 

public class ICalImpl extends UnicastRemoteObject implements ICal {protected ICalImpl() throws RemoteException {super();}private static final long serialVersionUID = 1L;@Overridepublic int sum(int add1, int add2) throws RemoteException {System.out.println("server : add1=" + add1 + ",add2=" + add2);return add1 + add2;}}

 

public interface IHello extends Remote {public String sayHello(String name) throws RemoteException;}

 

public class IHelloImpl extends UnicastRemoteObject implements IHello {private static final long serialVersionUID = 1L;protected IHelloImpl() throws RemoteException {super();}@Overridepublic String sayHello(String name) throws RemoteException {System.out.println("server : " + name + " come here ");return "hello " + name;}}

 

3. 启动RMI注册服务,并注册远程对象(Server.java)

public class Server {public static void main(String[] args) {//声明我要暴露的对象try {ICal    cal = new ICalImpl();IHello  hello = new IHelloImpl();        //本地主机上的远程对象注册表Registry的实例,并指定端口为 1100,//这一步必不可少(Java默认端口是1099),必不可缺的一步,缺少注册表创建,则无法绑定对象到远程注册表上             LocateRegistry.createRegistry(1100);             Naming.bind("rmi://127.0.0.1:1100/IHello",hello);            Naming.bind("rmi://127.0.0.1:1100/ICal",cal);                        System.out.println("Server already be started up ");} catch (RemoteException e) {e.printStackTrace();} catch (MalformedURLException e) {e.printStackTrace();} catch (AlreadyBoundException e) {e.printStackTrace();}}}

 

4. 客户端查找远程对象,并调用远程方法(RmiClient.java)

 

客户端只需要保有业务接口,不应该保有业务类的实现类。这样做的好处是一端服务器端业务实现发生了改变,而客户端可以通过RMI来获得改变的具体业务对象,所以这样我们可以在客户端执行大量的操作,可以只将持久化操作交由服务器。

 

public class RmiClient {public static void main(String[] args) {try {ICal cal = (ICal)Naming.lookup("rmi://127.0.0.1:1100/ICal");IHello hello = (IHello)Naming.lookup("rmi://127.0.0.1:1100/IHello");System.out.println(cal.sum(2, 3));System.out.println(hello.sayHello("kaobian"));} catch (MalformedURLException e) {e.printStackTrace();} catch (RemoteException e) {e.printStackTrace();} catch (NotBoundException e) {e.printStackTrace();}}}

 

 5. 执行程序:启动服务Server;运行客户端RmiClient进行调用

 

运行结果:

1、启动Server: Server already be started up 

2、启动RmiClient : 

Server :

server : add1=2,add2=3

server : kaobian come here 

Client:

5

hello kaobian

 

备注:RMI是线程同步的,即获取远程对象,执行其方法,server端如果一直没有返回值,则客户端一直等待返回的结果,可以使用debug模式测试一下。

 

lookup("Hello")默认为从本机 127.0.0.1的1099端口上查找Hello命令对象

lookup("192.168.1.105/Hello")与原语句是同等的,因为默认端口号就是1099。

HelloInterface hello = (HelloInterface)Naming.lookup("//192.168.1.105:1099/Hello");

 

  • 大小: 34.9 KB
  • 查看图片附件
原创粉丝点击