一、编写Java RMI分布式应用程序的步骤主要包括以下几步:
(1) 将远程类的功能定义为Java接口。在Java中,远程对象是实现远程接口的类的实例。在远程接口中声明每个要远程调用的方法。远程接口具有如下特点:1) 远程接口必须声明为public。如果不这样,则除非客户端与远程接口在同一个包内,否则当试图装入实现该远程接口的远程对象时会得到错误结果。2) 远程对象扩展java.rmi.Remote接口。3) 除了所有应用程序特定的例外之外,每个方法还必须抛出java.rmi.RemoteException例外。4) 任何作为参数或返回值传送的远程对象的数据类型必须声明为远程接口类型,而不是实现类。
(2) 编写和实现服务器类。该类是实现(1)中定义的远程接口。所以在该类中至少要声明实现一个远程接口,并且必须具有构造方法。在该类中还要实现远程接口中所声明的各个远程方法。
(3) 编写使用远程服务的客户机程序。在该类中使用java.rmi.Naming中的lookup()方法获得对远程对象的引用,依据需要调用该引用的远程方法,其调用方式和对本地对象方法的调用相同。
实现了服务器和客户机的程序后,就是编译和运行该RMI系统。其步骤有:
(1) 使用javac编译远程接口类,远程接口实现类和客户机程序。
(2) 使用rmic编译器生成实现类的stub和skeleton。
(3) 启动RMI注册服务程序rmiregistry。
(4) 启动服务器端程序。
(5) 启动客户机程序。
二、实例代码:
//服务端接口程序
//IServer.java
package test;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface IServer extends Remote {
long getTime() throws RemoteException;
}
//服务端实现程序
//ServerImpl.java
package test;
import java.rmi.Naming;
import java.rmi.RMISecurityManager;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
public class ServerImpl extends UnicastRemoteObject implements IServer {
public ServerImpl() throws RemoteException {
super();
}
public long getTime() throws RemoteException {
return System.currentTimeMillis();
}
public static void main(String[] args) {
/* 创建和安装一个安全管理器,令其支持RMI.作为Java开发包的一部分,适用于RMI唯一一个是RMISecurityManager. */
System.setSecurityManager(new RMISecurityManager());
try {
/* 创建远程对象的一个或多个实例,下面是PerfectTime对象 */
ServerImpl server = new ServerImpl();
/* 向RMI远程对象注册表注册至少一个远程对象。一个远程对象拥有的方法即可生成指向其他远程对象的句柄,这样,客户到注册表里访问一次,得到第一个远程对象即可. */
Naming.rebind("RMIServer", server);
System.out.println("Ready to getTime");
} catch (Exception e) {
e.printStackTrace();
}
}
}
//客户端调用程序
//TestClient.java
package test;
import java.rmi.Naming;
import java.rmi.RMISecurityManager;
public class TestClient {
public TestClient() {
super();
}
public static void main(String[] args) {
System.setSecurityManager(new RMISecurityManager());
try {
IServer server = (IServer) Naming.lookup("RMIServer");
for (int i = 0; i < 10; i++) {
System.out.println("PerfectTime:" + server.getTime());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
三、运行示例:
1.创建Stub和Skeleton:
rmic -d . test.ServerImpl
若运行成功,则会在test目录下生成两个类ServerImpl_Stub.class和ServerImpl_Skel.class
2.启动RMI注册(Registry)程序:
start rmiregistry
3.启动服务器程序:
java test.ServerImpl
4.运行客户端调用程序:
java test.TestClient
四、一些常见的异常及处理办法:
1.
problem: You get a "class not found" error when running rmic
solution: Add the current directory to your classpath.
2.
problem: You get the following error when running the client
Exception occured: java.rmi.UnmarshalException: Return value class not found; nested exception is:
java.lang.ClassNotFoundException: myRMIImpl_Stub
solution: The file myRMIImpl_Stub.class must be deployed with your client application (that is, you must place it somewhere in the classpath of the client machine; If you were using an applet as a client, you would place it in the directory specified in the CODEBASE parameter to achieve the same effect).
3.
problem: You get the following error when running the client
C:/test3>java myRMIClient 127.0.0.1
Exception occured: java.security.AccessControlException: access denied (java.net
.SocketPermission 127.0.0.1:1099 connect,resolve)
or the following when running the server
C:/test3>java myRMIServer
Exception occurred: java.security.AccessControlException: access denied (java.ne
t.SocketPermission 127.0.0.1:1099 connect,resolve)
solution: I experienced this problem under Java2 with the default security policy in place. You'll need to modify your security policy to allow these activities to take place. A full writeup on this is available at The Sun RMI tutorial page.
In summary, you'll need to do the following:
(1)Create a new security policy file. See your JDK docs or the links referenced from the Sun RMI tutorial for more information on this.
(2)When you run the client or the server, pass the location of your new security policy file in as an argument. This allows you to run under a new policy without having to modify your system policy files. Here is a .policy file that grants all permissions to everybody. DO NOT install this policy file in a production system. However, you can use it in trivial testing. You can then run the server with the command line
java -Djava.security.policy=c:/test3/wideopen.policy myRMIServer
or the client with
java -Djava.security.policy=c:/test3/wideopen.policy myRMIClient 127.0.0.1
Of course, you'd replace c:/test3/wideopen.policy with the full path to your own properties file.
Here is another policy file that includes only the permissions necessary to run this app.
参考资料:
http://www.ccs.neu.edu/home/kenb/com3337/rmi_tut.html
http://www.huihoo.com/java/rmi/
http://patriot.net/~tvalesky/easyrmi.html
http://www.javajia.com/article.php?id=389
http://www.delfan.com/language/java/apps/rmi.html
http://www.itonline.gd.cn/ittech/list.asp?id=117