﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-codefans-文章分类-java technology</title><link>http://www.blogjava.net/codefans/category/6276.html</link><description /><language>zh-cn</language><lastBuildDate>Tue, 27 Feb 2007 08:51:15 GMT</lastBuildDate><pubDate>Tue, 27 Feb 2007 08:51:15 GMT</pubDate><ttl>60</ttl><item><title>RMI入门 </title><link>http://www.blogjava.net/codefans/articles/32373.html</link><dc:creator>春雷的博客</dc:creator><author>春雷的博客</author><pubDate>Sat, 25 Feb 2006 03:11:00 GMT</pubDate><guid>http://www.blogjava.net/codefans/articles/32373.html</guid><wfw:comment>http://www.blogjava.net/codefans/comments/32373.html</wfw:comment><comments>http://www.blogjava.net/codefans/articles/32373.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/codefans/comments/commentRss/32373.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/codefans/services/trackbacks/32373.html</trackback:ping><description><![CDATA[来源：http://ybwen.home.chinaren.com<BR><BR>
<P>为通过网络执行其他机器上的代码，传统的方法不仅难以学习，而且易出错。解决这个问题的最佳方法是：某些对象正好位于另一台机器，我们可以发送一条消息，并获得返回结果，就像位于自己的本机器一样。<SPAN lang=EN-US>Java远程方法调用(RMI)特性使客户机上运行的程序可以调用远程服务器上的对象。远程方法调用特性使Java编程人员能够在网络环境中分布操作。</SPAN></P>
<P>下面介绍一下必要的步骤，创建自己的<SPAN lang=EN-US>RMI对象。</SPAN></P>
<H3>一、远程接口概念：</H3>
<P><SPAN lang=EN-US><SPAN>&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>RMI对接口有着强烈的依赖。在需要创建一个远程对象的时候，我们通过传递一个接口来隐藏基层的实施细节。所以客户得到远程对象的一个句柄正好同一些本地的根代码连接，有后者负责通过网络通信。但我们并不关心这些事情，通过自己的接口句柄发送消息即可。</SPAN></P>
<P><SPAN lang=EN-US><SPAN>&nbsp;&nbsp; </SPAN>创建一个远程接口时，必须遵守下列规则：</SPAN></P>
<P><SPAN lang=EN-US>1)<SPAN Roman?? New Times>&nbsp; </SPAN>远程接口必须为<SPAN lang=EN-US>public属性(不能有“包访问”；也就是说，他不能是“友好的”)。否则，一旦客户试图装载一个实现了远程接口的远程对象，就会得到一个错误。</SPAN></P>
<P><SPAN lang=EN-US>2)<SPAN Roman?? New Times>&nbsp; </SPAN>远程接口必须扩展接口<SPAN lang=EN-US>java.rmi.Remote。</SPAN></P>
<P><SPAN lang=EN-US>3)<SPAN Roman?? New Times>&nbsp; </SPAN>除与应用程序本身有关的违例，远程接口中的每个方法都必须在自己的<SPAN lang=EN-US>throws从句中声明java.rmi.RemoteException.</SPAN></P>
<P><SPAN lang=EN-US>4)<SPAN Roman?? New Times>&nbsp; </SPAN>作为参数或返回值传递的一个远程对象<SPAN lang=EN-US>(不管是直接，还是本地对象中嵌入)必须声明为远程接口，不可声明为实施类。</SPAN></P>
<P>下面是一个远程接口示例，</P>
<P><SPAN lang=EN-US>//PerfectTimeI.java <BR></SPAN><SPAN lang=EN-US>//The PerfectTime remote interface <BR></SPAN><SPAN lang=EN-US>package rmi.sample.server; <BR></SPAN><SPAN lang=EN-US>import java.rmi.*; <BR></SPAN><SPAN lang=EN-US>public interface PerfectTimeI extends Remote {&nbsp;<BR></SPAN><SPAN lang=EN-US><SPAN>&nbsp;&nbsp;&nbsp; </SPAN>long getPerfectTime() throws RemoteException; <BR></SPAN><SPAN lang=EN-US>} </SPAN></P>
<P><SPAN>它表面上与其他的接口类似，只是对<SPAN lang=EN-US>Remote进行了扩展，而且所有的方法都会“掷”出RemoteException.接口和方法都是Public的。 </SPAN></P>
<P>编译<SPAN lang=EN-US>PerfectTimeI.java,生成PerfectTimeI.class(test是包，编译时注意路径)</SPAN></P>
<P><SPAN lang=EN-US>javac rmi.sample.server.PerfectTimeI.java </SPAN></P>
<H3>二、远程接口的实施：</H3>
<P><SPAN lang=EN-US><SPAN>&nbsp;&nbsp;&nbsp; </SPAN>服务器必须包含一个扩展了UnicastRemoteObject类，并实现远程接口。这个类也可以含有附加的方法，但客户只能使用远程接口中的方法。因为客户是指向接口的一个句柄，而不是它的哪个类。</SPAN></P>
<P><SPAN lang=EN-US><SPAN>&nbsp;&nbsp; </SPAN>必须为远程对象定义构件器，即使只准备定义一个默认构件器，用它调用基础类构件器。必须把它明确地编写出来，因为它必须“掷”出RemoteException违例。</SPAN></P>
<P><SPAN lang=EN-US><SPAN>&nbsp; </SPAN>下面列出远程接口PerfectTime的事实过程：他代表精确计时服务</SPAN></P>
<P><SPAN lang=EN-US>//PerfectTime.java </SPAN></P>
<P><SPAN lang=EN-US>//The implementation of the PerfectTime remote object </SPAN></P>
<P><SPAN lang=EN-US>package rmi.sample.server; </SPAN></P>
<P><SPAN lang=EN-US>import java.net.*; <BR></SPAN><SPAN lang=EN-US>import java.rmi.*; <BR></SPAN><SPAN lang=EN-US>import java.rmi.registry.*; <BR></SPAN><SPAN lang=EN-US>import java.rmi.server.*; <BR></SPAN><SPAN lang=EN-US>public class PerfectTime extends UnicastRemoteObject implements PerfectTimeI </SPAN><SPAN lang=EN-US>{ <BR></SPAN><SPAN lang=EN-US>//默认构件器，也要“掷”出RemoteException违例。&nbsp;<BR></SPAN><SPAN lang=EN-US><SPAN>&nbsp;&nbsp;&nbsp; </SPAN>public PerfectTime() throws RemoteException {&nbsp;<BR></SPAN><SPAN lang=EN-US><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>super();&nbsp;<BR></SPAN><SPAN lang=EN-US><SPAN>&nbsp;&nbsp;&nbsp; </SPAN>} </SPAN></P>
<P><SPAN lang=EN-US>public long getPerfectTime() throws RemoteException {&nbsp;<BR></SPAN><SPAN lang=EN-US><SPAN>&nbsp;&nbsp;&nbsp; </SPAN>return System.currentTimeMillis(); <BR></SPAN><SPAN lang=EN-US>} </SPAN></P>
<P><SPAN lang=EN-US>public static void main(String[] args) { <BR></SPAN><SPAN lang=EN-US>/*创建和安装一个安全管理器，令其支持RMI.作为Java开发包的一部分，适用于RMI唯一一个是RMISecurityManager.*/&nbsp;<BR></SPAN><SPAN lang=EN-US><SPAN>//&nbsp;&nbsp;&nbsp; </SPAN>System.setSecurityManager(new RMISecurityManager()); </SPAN></P>
<P><SPAN lang=EN-US><SPAN>&nbsp;&nbsp;&nbsp; </SPAN>try {&nbsp;<BR></SPAN><SPAN lang=EN-US><SPAN>&nbsp;&nbsp; </SPAN>/*创建远程对象的一个或多个实例，下面是PerfectTime对象*/&nbsp;<BR></SPAN><SPAN lang=EN-US><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>PerfectTime pt = new PerfectTime();&nbsp;<BR></SPAN><SPAN lang=EN-US><SPAN>&nbsp;&nbsp; </SPAN>/*向RMI远程对象注册表注册至少一个远程对象。一个远程对象拥有的方法即可生成指向其他远程对象的句柄，这样，客户到注册表里访问一次，得到第一个远程对象即可.*/&nbsp;<BR></SPAN><SPAN lang=EN-US><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>Naming.bind("PerfectTime", pt);&nbsp;<BR></SPAN><SPAN lang=EN-US><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>System.out.println("Ready to do Time");&nbsp;<BR></SPAN><SPAN lang=EN-US><SPAN>&nbsp;&nbsp;&nbsp; </SPAN>} catch (Exception e) {&nbsp;<BR></SPAN><SPAN lang=EN-US><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>e.printStackTrace();&nbsp;<BR></SPAN><SPAN lang=EN-US><SPAN>&nbsp;&nbsp;&nbsp; </SPAN>} <BR></SPAN><SPAN lang=EN-US>} <BR></SPAN><SPAN lang=EN-US>} </SPAN></P>
<P>编译<SPAN lang=EN-US>PerfectTime.java,生成PerfectTime.class(rmi.sample.server是包，编译时注意路径)<BR></SPAN><SPAN lang=EN-US>javac rmi.sample.server.PerfectTime.java </SPAN></P>
<H3>三、创建根和干：</H3>
<P><SPAN lang=EN-US><SPAN>&nbsp; </SPAN>创建RemoteObject的主干和框架。要完成这个工作可使用rmic编译器，</SPAN><SPAN lang=EN-US>rmic编译器生成远程对象的存根和骨架。存根（Stub）是远程对象在客户端的代理，它将RMI调用传递给服务器端的骨架（Skeleton），后者负责将该调用传递给实际的远程方法</SPAN>输入如下：</P>
<P><SPAN lang=EN-US>rmic rmi.sample.server.PerfectTime</SPAN></P>
<P><SPAN lang=EN-US><SPAN>&nbsp;</SPAN>执行这个命令，</SPAN></P>
<P>若<SPAN lang=EN-US>rmic成功运行，rmi.sample.server目录里就会多出两个新类：</SPAN></P>
<P><SPAN lang=EN-US>PerfectTime_Stub.class <BR></SPAN><SPAN lang=EN-US>PerfectTime_Skel.class </SPAN></P>
<P>它们分别对应的是根<SPAN lang=EN-US>(stub)和骨架(skeleton).</SPAN></P>
<H3>四、使用远程对象：</H3>
<P><SPAN lang=EN-US>RMI全部的宗旨就是可能简化远程接口对象的使用。我们客户程序中要做的唯一一件额外事情是查找从服务器取回远程接口。下面就是编写的Java程序：将消息发给对象：</SPAN></P>
<P><SPAN lang=EN-US>//DisplayPerfectTime.java <BR></SPAN><SPAN lang=EN-US>//Users remote object PerfectTime </SPAN></P>
<P><SPAN lang=EN-US>package rmi.sample.client; <BR></SPAN><SPAN lang=EN-US>import java.rmi.*; <BR></SPAN><SPAN lang=EN-US>import java.rmi.registry.*; <BR></SPAN><SPAN lang=EN-US>public class DisplayPerfectTime { <BR></SPAN><SPAN lang=EN-US>/*** DisplayPerfectTime 构造子注解。*/ <BR></SPAN><SPAN lang=EN-US>public DisplayPerfectTime() {&nbsp;<BR></SPAN><SPAN lang=EN-US><SPAN>&nbsp;&nbsp;&nbsp; </SPAN>super(); <BR></SPAN><SPAN lang=EN-US>} </SPAN></P>
<P><SPAN lang=EN-US>public static void main(String[] args) {&nbsp;<BR></SPAN><SPAN lang=EN-US><SPAN>&nbsp;&nbsp;&nbsp;// </SPAN>System.setSecurityManager(new RMISecurityManager());&nbsp;<BR></SPAN><SPAN lang=EN-US><SPAN>&nbsp;&nbsp;&nbsp; </SPAN>try {&nbsp;<BR></SPAN><SPAN lang=EN-US><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>PerfectTimeI t = (PerfectTimeI) Naming.lookup("PerfectTime");&nbsp;<BR></SPAN><SPAN lang=EN-US><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>for (int i = 0; i &lt; 10; i++) {&nbsp;<BR></SPAN><SPAN lang=EN-US><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN>&nbsp;&nbsp;&nbsp; </SPAN>System.out.println("PerfectTime:" + t.getPerfectTime());&nbsp;<BR></SPAN><SPAN lang=EN-US><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>}&nbsp;<BR></SPAN><SPAN lang=EN-US><SPAN>&nbsp;&nbsp;&nbsp; </SPAN>} catch (Exception e) {&nbsp;<BR></SPAN><SPAN lang=EN-US><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>e.printStackTrace();&nbsp;<BR></SPAN><SPAN lang=EN-US><SPAN>&nbsp;&nbsp;&nbsp; </SPAN>} <BR></SPAN><SPAN lang=EN-US>}<BR></SPAN><SPAN lang=EN-US>} </SPAN></P>
<P>编译<SPAN lang=EN-US>DisplayPerfectTime.java.<BR></SPAN><SPAN lang=EN-US>javac rmi.sample.client.DisplayPerfectTime.java </SPAN></P>
<H3>五、启动注册并运行代码：</H3>
<P>在运行<SPAN lang=EN-US>PerfectTime类和DisplayPectTime类之前，用户必须首先在将要宿主PerfectTime的计算机上启动RMI注册(Registry)程序，即使将要运行PerfectTime的计算机与运行DisplayPerfectTime的是同一台机器,这一步也是必须的。注册表服务器的名字是rmiregistry.在32位Windows环境中，可使用： start rmiregistry 令其在后台运行。然后分别开两个不同的进程运行Server端和Client端：启动注册表服务器：</SPAN></P>
<P><SPAN lang=EN-US>start rmiregistry </SPAN></P>
<P>绑定<SPAN lang=EN-US>PerfectTime到注册，运行服务端程序：在Windows下，输入下列命令，在后台启动PerfectTime程序：</SPAN></P>
<P><SPAN lang=EN-US>java rmi.sample.server.PerfectTime </SPAN></P>
<P><SPAN lang=EN-US>Ready to do Time </SPAN></P>
<P>运行客户端程序：如下</P>
<P><SPAN lang=EN-US>G:\RMI&gt;java rmi.sample.client.DisplayPerfectTime </SPAN></P>
<P><SPAN lang=EN-US>PerfectTime:961722589649 <BR></SPAN><SPAN lang=EN-US>PerfectTime:961722589669 <BR></SPAN><SPAN lang=EN-US>PerfectTime:961722589679 <BR></SPAN><SPAN lang=EN-US>PerfectTime:961722589679 <BR></SPAN><SPAN lang=EN-US>PerfectTime:961722589689 <BR></SPAN><SPAN lang=EN-US>PerfectTime:961722589689 <BR></SPAN><SPAN lang=EN-US>PerfectTime:961722589689 <BR></SPAN><SPAN lang=EN-US>PerfectTime:961722589699 <BR></SPAN><SPAN lang=EN-US>PerfectTime:961722589699 <BR></SPAN><SPAN lang=EN-US>PerfectTime:961722589699 <BR><BR>RMI程序要注意以下几点：<BR>1，rmiregistry必须要能够找到stub,skeleton<BR>2，若RMI涉及到Socket读写，必须自己写一个Java策略文件。</SPAN></P></SPAN></SPAN></SPAN></SPAN></SPAN><img src ="http://www.blogjava.net/codefans/aggbug/32373.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/codefans/" target="_blank">春雷的博客</a> 2006-02-25 11:11 <a href="http://www.blogjava.net/codefans/articles/32373.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>