JAVA RMI 文档中文(三)

2.7 远端对象的定位

一个简单的命名服务器可以存储命名的远端对象的引用。java.rmi.Naming可以使用以URL为基础的方法存储一个远端对象的引用。

对于客户端来说,如果要调用远端对象的方法的话,那么需要先获取到远端对象的引用。一个远端引用通常可以作为方法调用的参数或者返回值来获取。RMI系统提供了简单的命名服务器,它用于从指定的主机上获取远端对象。java.rmi.Naming提供了一系列基于URL的方法(look up, bind, rebind, unbind, list),这些方法用于操作指定主机和端口下维护的 对象-名称 对。

3.1 存根和骨架Stubs and Skeletons
(后面这两个词还是直接用英文吧)

RMI使用了标准的远程通信机制:stubs and skeletons。stub相当于远端对象在客户端的代理。当用户调用本地的stub上的方法,stub就要负责执行远端对象的该方法。对应于远端对象的stub需要实现远端对象实现的所有接口。

当一个stub中的方法被调用时,stub会做下面的事:

1、与拥有远端对象的远端虚拟机创建连接。
2、发送参数到远端虚拟机。
3、等待返回结果。
4、获取返回结果或者异常信息
5、将返回结果返回给用户。

stub隐藏了参数序列化和网络级的通信细节,这样是为了让用户可以方便使用。

在远端虚拟机中,每一个远端对象可能会有一个相对应的skeleton(在 java2 平台环境下(java 2 platform-only),skeleton不是必须的)。skeleton负责分发调用到真正的远端对象实现。当一个skeleton接收到一个方法请求时,skeleton会做如下事:

1、获取远端方法的参数。
2、调用实际远端方法实现。
3、传递结果给调用者。

java1.2中增加了额外的stub协议,该协议消除了Java 2平台环境中对框架的需求。在JDK1.1中却相反,通常都是使用skeleton来实现任务。Stub和Skeleton通过rmic编译器生成。

3.2 在远端方法调用中线程的使用

在RMI运行时,方法分配到远端实现可能在一个线程中或者不在一个线程。RMI运行时不能保证远端对象和线程的映射关系。因为同一个远端对象的远端方法可能会同时执行,所以一个远端对象在实现时需要确保线程安全。

3.3 远端对象的垃圾回收机制

和在本地系统一样,在分布式系统中,我们也希望远端对象可以自动删除,可以不再被客户端引用。远端对象可以在合适的时候自动删除,这样的话,程序员就可以不用跟踪远端对象了。RMI使用了引用计数垃圾回收算法,它与Modula-3`s Network Objects有些相似。

为了实现引用计数的垃圾回收算法,RMI在运行时会跟踪所有每个虚拟机中存活的引用。当一个活的引用进入虚拟机时,它的(这里指的是该引用)引用计数就增加。一个对象的第一个引用会发送“已引用”的信息到服务端The first reference to an object sends a “referenced” message to the server for the object。在本地虚拟机中当引用变为未被引用时,引用计数就会减少。当最后一个引用死掉的时候,会发送一个未被引用的信息给服务端。当然协议中还有很多细节。所有这些协议都是通过维持引用的顺序和未被引用消息来保证对象不会被过早的回收。

当一个远端对象没有被任何客户端引用,RMI在运行时会将其视为弱引用。弱引用允许虚拟机的垃圾回收器在没有其他本地对象引用它的情况下,丢弃该对象。分布式垃圾回收算法和本地虚拟机的垃圾回收器通过维护对象正常的引用或者弱引用来相互作用。

只要本地存在对远端对象的引用,那么该对象就不能被回收,而且它可以在方法调用中被传递。通过传递远程对象将虚拟机的标识传到引用的集合中。一个远端对象必须实现java.rmi.server.Unreferenced接口才会有取消引用通知。当引用不存在的时候,unreferenced方法就会被调用。unreferenced方法在引用集为空的时候被调用,所以该方法可能会被调用多次。远端对象只有在本地或者远端的引用不存在的时候才会被回收。

注意,如果在服务端和客户端之间存在网络分区,那么可能会出现过早回收远端对象的情况(因为在传输过程中可能会认为客户端已经崩溃了)。由于这种可能,远端引用不能保证引用的完整性;换句话说,一个远端引用可能会指向一个不存在的对象。一旦出现这种情况,就会抛出RemoteException异常,该异常必须有应用来处理。

web报表工具 请移步:http://download.csdn.net/source/2881508 不多说,除了RMI的学习外,gui对新手入门也是个不错的学习 /* *此类适合在本地注册的RMI服务器,避免了使用了多个DOS的写法,只需要简单的给使用 *本类提供的方法即可。 */ package common.rmiserver; import java.rmi.Naming; import java.rmi.NotBoundException; import java.rmi.Remote; import java.rmi.registry.Registry; import java.rmi.registry.LocateRegistry; //import java.rmi.RMISecurityManager; import java.rmi.RemoteException; import java.net.MalformedURLException; import java.rmi.server.UnicastRemoteObject; import common.zip.ZipClientSocketFactory; import common.zip.ZipServerSocketFactory; public final class RMIServer { private Registry registry = null; // @jve:decl-index=0: private String serverName = "RMIServer"; private String serverPath = "localhost"; private int port = 1099; private Remote serverInterface = null; private Boolean isStart = false; private AllFace dataAllFace = null; private int dataPort = 0;// 数据端口,0表示端口由RMI服务器动态生成. private Remote stub; public RMIServer() { } /* * 使用默认端口,默认服务器名称,服务路径构造函数 use the default port,server name and the url */ public RMIServer(Remote obj) { this.serverInterface = obj; } /* * 使用默认端口,服务路径构造函数 use the default port and server url */ public RMIServer(String servername, Remote obj) { this.serverName = servername; this.serverInterface = obj; } /* * 服务器为默认值的构造函数 use the default url */ public RMIServer(String servername, int port, Remote obj) { this.port = port; this.serverName = servername; this.serverInterface = obj; } /* * 适合1.4范围的版本,当然也适合5.0的版本 */ public Boolean setStart() throws RemoteException, MalformedURLException, NotImplementInterfaceException { if (registry == null) registry = LocateRegistry.createRegistry(port); if (serverInterface == null) { throw new NotImplementInterfaceException( "not found the reote interface method!!"); } Naming.rebind("rmi://"+serverPath + ":" + port + "/" + serverName, serverInterface); isStart = true; return isStart; } /* * jdk5.0以后的写法,在使用之前使用setXxx方法给对象赋值 */ public Boolean start() throws RemoteException, MalformedURLException, NotImplementInterfaceException { if(stub==null) stub = (Remote) UnicastRemoteObject.exportObject(dataAllFace, dataPort);// 0表示端口随机生成. if (registry == null) registry = LocateRegistry.createRegistry(port, new ZipClientSocketFactory(), new ZipServerSocketFactory()); setProperty(serverPath); //绑定IP registry.rebind(serverName, stub); isStart = true; return isStart; } /* * 如果有多个ip,则使用这个方法绑定指定的IP */ public void setProperty(String ip) { System.setProperty("java.rmi.server.hostname", ip); } /* * close the server */ public void close() throws RemoteException, MalformedURLException, NotBoundException { //UnicastRemoteObject.unexportObject(dataAllFace, true); Naming.unbind("rmi://"+serverPath + ":" + port + "/" + serverName); isStart = false; } /* * set server name,if not set the name,the service will use the default name * "RMIServer" */ public void setServerName(String serverName) { this.serverName = serverName; } /* * set the server URL,default localhost "rmi://localhost" */ public void setServerPath(String serverPath) { this.serverPath = serverPath; } /* * set the server port default port is 1099. */ public void setPort(int port) { this.port = port; } /* * set then remote implement method */ public void setServerInterface(Remote serverInterface) { this.serverInterface = serverInterface; } /* * set the server Security */ public void setSecurityManager() { /* if (System.getSecurityManager() == null) { try { // java -Djava.security.policy=policy.txt // common.rmiserver.RMIServer System.setSecurityManager(new RMISecurityManager());// 暂时不要安全设置, } catch (java.rmi.RMISecurityException exc) { throw exc; } }*/ } /* * set the remote method */ public void setDataAllFace(AllFace dataAllFace) { this.dataAllFace = dataAllFace; } /* * set the remote dataport */ public void setDataPort(int dataPort) { this.dataPort = dataPort; } // ----------------------------------------------- /* * return the server URL */ public String getServerPatth() { return serverPath; } /* * return remote method */ public Remote getserverInterface() { return serverInterface; } /* * return the server name */ public String getServerName() { return serverName; } /* * return the server use port */ public int getPort() { return port; } /* * return the server then action state */ public Boolean isStart() { return isStart; } /* * return remote method */ public AllFace getDataAllFace() { return dataAllFace; } /* * return remote dataport */ public int getDataPort() { return dataPort; } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值