使用RMI进行分布式交互

王朝学院·作者佚名  2016-08-27
窄屏简体版  字體: 小  |  中  |  大  |  超大  

内容概要:

RMI 示例RMI 架构RMI APIRemoteRemoteExceptionRegistry, LocateRegistryNaming

RMI 示例

在了解RMI之前,先来看一个例子:

//服务接口packagecom.fjn.java.rmi.quickstart.server;importjava.rmi.Remote;importjava.rmi.RemoteException;publicinterfaceHelloextendsRemote{publicString sayHello(String str)throwsRemoteException;

}//服务实现packagecom.fjn.java.rmi.quickstart.server;importjava.io.Serializable;importjava.rmi.RemoteException;publicclassHelloImplimplementsHello, Serializable {PRotectedHelloImpl()throwsRemoteException {super();

}privatestaticfinallongserialVersionUID = 3556503295294925414L;

@OverridepublicString sayHello(String str) {return"Hello, "+str;

}

}//Server端发布服务:packagecom.fjn.java.rmi.quickstart.server;importjava.net.MalformedURLException;importjava.rmi.AlreadyBoundException;importjava.rmi.NotBoundException;importjava.rmi.RemoteException;importjava.rmi.registry.LocateRegistry;importjava.rmi.registry.Registry;importjava.rmi.server.UnicastRemoteObject;publicclassServerTest {publicstaticvoidmain(String[] args)throwsRemoteException, AlreadyBoundException, InterruptedException, MalformedURLException, NotBoundException {//创建RegistryRegistry registry=LocateRegistry.createRegistry(9998);

Hello stub=(Hello) UnicastRemoteObject.exportObject(newHelloImpl(),0);//将ref绑定到registry中registry.rebind("Hello", stub);

Hello stub2=(Hello)registry.lookup("Hello");

System.out.println(stub2);

Thread.sleep(1000*60*60);

}

}

执行结果:

Hello, zhang san

Hello, Zhang san

RMI 架构

上面的这个图表示了RMI的架构图,设计说明:Server端只需向一个登记处(Registry)为一个远程对象注册名字(唯一),然后就可以等待客户端来使用了。客户端要调用一个远程方法前,先去登记处(Registry)look up(根据name),找到相应的对象(找到的是对象的引用),然后在客户端进行方法调用。因为客户端拿到的是远程对象的引用,所以就像是直接调用一样。

在有些情况下,客户端会从服务端取一此Class的bytecode,服务端同样也会从客户端取一些类的bytecode。这样做的前提是,对方那里有Web Server。获取时使用都是URL协议:URL protocol (e.g., HTTP, FTP, file, etc.) 。

RMI APIRemoteTheRemoteinterface serves to identify interfaces whose methods may be invoked from a non-local virtual machine. Any object that is a remote object must directly or indirectly implement this interface. Only those methods specified in a "remote interface", an interface that extendsjava.rmi.Remoteare available remotely.

在这个接口中,没有任何方法。这个接口只是一个标记作用,标记那些可以在非本地使用的接口。也就是说,如果这个接口可以被RMI客户端使用,就必须extends这个接口,或者Remote的子接口。

将实现了Remote接口的对象称为远程对象。RMI用于分布式程序,因此也将远程对象称为分布式对象。

远程接口的设计原则:

1)必须继承Remote接口

2)在远程接口中声明的方法必须满足下列要求:

A:方法必须抛出java.rmi.RemoteException(IOException,Exception也可以,因为这两个异常是RemoteException的父类)。

B:远程方法的声明中:如果远程对象出现参数或者返回值中,那么得使用远程接口本身。

3)远程接口如果也继承了其他的非远程接口,只要远程方法满足2)中的要求即可。作为远程接口本身,要继承Remote接口,在这个远程接口中直接声明的方法要满足2)中的要求。从非远程接口中继承来的方法也得满足2)中的要求。

4)接口的实现,必须实现Serializable接口。

RemoteException 为了保证远程调用时,程序的正常进行,需要对每一个远程方法都抛出RemoteException,或者它的父类:IOException、Exception。

何时会抛出RemoteException?

1) 协议错误时

2) 通信失败时(Server拒绝请求,或者没有连接成功)

3) 参数或者接口在marshall、unmarshall过程中出现问题

Registry、LocateRegistry

在前面已经知道Registry是一个登记处。用于登记提供的远程服务的。

Registry类提供了一些存储、获取远程对象(在存储时,远程对象的引用会与一个name绑定,name是唯一的,所以获取时可以根据name来获取)。

提供了下列方法:

bind、unbind、rebind 用于将远程对象与指定的name进行绑定和解绑。

list:用于列出已绑定的远程对象的name。返回结果是数组。

另外有一点很重要,在Registry中存储的是stub对象。而正在的对象是在RMI Server上。

当客户端通过Naming或者Registry查找(loopup)到的都是对象的stub。然后利用Stub的序列化与反序列化功能进行Client与Server端通信。

LocateRegistry与Registry的关系LocateRegistry是用于定位Registry在网络上的位置的,知道Registry在网络上的位置,就能取得Registry对象,根据Registry对象就可以找到要使用的远程对象,找到远程对象就可以去调用远程方法了。

Naming

Naming类提供了一些存储和获取远程对象(存储在Registry中的)的引用的方法。

提供的方法有:

提供的方法中,都有一个name参数,是字符串类型的。它是有一个标准的格式(是一个URL,但是少了URL中的schema部分,schema是rmi)。格式为:

//host:port/name 或者 rmi://host:port/name

Host就是定位到的Registry的host,端口也是。

从提供的方法上来看,Naming就是一个工具类,它提供的方法都是静态的,但是方法确实和Registry中的方法是一样的。如此,目前就学习了两种获取、绑定远程对象的方法了。

也就是说Registry在客户端和服务端都是可用的。绑定用于服务端,获取用于客户端。

方式一:

使用Registry绑定或者获取一个远程对象的stub。

方式二:

直接使用Naming来绑定或者获取一个远程对象的stub。

 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
© 2005- 王朝網路 版權所有 導航