最近在学习RMI的过程中发现了几个问题, 总结出来, 希望对学习RMI的朋友们有所助益.
对于RMI原理性的东西这里就不多说了, 网上也有很多好的文章。
首先,还是把这几个测试类写好, 如下四个类:
//远程接口类: Hello
import java.rmi.*;
// RMI本地接口必须从Remote接口派生
public interface Hello extends Remote {
// 接口中的具体方法声明,注意必须声明抛出RemoteException
String sayHello(String name) throws RemoteException;
}
//远程接口实现类:HelloImplement
import java.rmi.*;
import javax.rmi.PortableRemoteObject;
public class HelloImplement extends PortableRemoteObject implements Hello {
/* 构造函数 */
public HelloImpl() throws RemoteException {
super();
}
/* 实现本地接口中声明的'sayHello()'方法 */
public String sayHello(String message) throws RemoteException {
System.out.println("RMI的服务器端,客户端正在调用'sayHello'方法。 ");
System.out.println("Hello " + message);
return message;
}
}
//服务器类:HelloServer
import java.rmi.*;
public class HelloServer {
public static void main(String[] args) {
// 在服务器端设置安全机制
/*
if (System.getSecurityManager() == null) {
System.setSecurityManager(new RMISecurityManager());
}
*/
try {
System.out.println("开始 RMI Server ...");
/* 创建远程对象的实现实例 */
Hello hImpl = new HelloImplement();
System.out.println("将实例注册到专有的URL ");
Naming.rebind("rmi://10.40.12.18.:1099/HelloService", hImpl);
System.out.println("等待RMI客户端调用...");
} catch (Exception e) {
System.out.println("错误: " + e);
}
}
}
//客户端类:HelloClient
import java.rmi.*;
public class HelloClient {
public static void main(String[] args) {
// 在服务器端设置安全机制
/*
if (System.getSecurityManager() == null) {
System.setSecurityManager(new RMISecurityManager());
}
*/
/* 默认端口1099 */
try {
/* 根据指定的URL定位远程实现对象 */
/* “h”是一个标识符,我们将用它指向实现“Hello”接口的远程对象 */
Hello h = (Hello)Naming.lookup("rmi://10.40.12.18/HelloService");
h.sayHello(" RMI");
} catch (Exception ex) {
System.out.println("错误 " + ex);
}
}
}
测试RMI
1: 将上面四个文件放在同一个目录下编译: javac *.java
2:打开一个新的DOS窗口,使用命令rmic 产生根程序(Stub) 和框架程序(Skel): rmic HelloImplement
3:打开一个新的DOS窗口,使用命令rmiregistry注册类: rmiregistry
4:打开一个新的DOS窗口,运行HelloServer: java HelloServer
5:打开一个新的DOS窗口,运行HelloClient: java HelloClient
6:最后打印出Hello RMI
需要特别注意的地方: 环境变量的设置;在使用rmiregistry命令之前, 一定要把环境JDK环境变量设置好。主要有如下变量需要设置(我使用的是JBuilder自带的JDK):
JAVA_HOME 值: C:/JBuilderX/jdk1.4
JAVA_PATH 值: .;%JAVA_HOME%/jre/bin;
CLASS_PATH 值 .;%JAVA_HOME%/bin;%JAVA_HOME%/jre/lib;C:/JBuilderX/jdk1.4/lib/dt.jar;C:/JBuilderX/jdk1.4/lib/tools.jar;
在Path环境变量最前面写上 .;%JAVA_HOME%/bin;
同时需要把你的RMI工作目录设入环境变量CLASS_PATH 和Path中去;
*** 如果你安装了oracle 、Webogic 等自带JDK的服务器或是工具, 它们也会将JDK目录设置到环境变量中,这样一来,假设你使用的JB的JDK,然而环境变量也设置好了, 使用rmiregistry 不一定是JB 所带的JDK的命令,而有可能是其它工具中的JDK。 如果是这样的话, 使用java HelloServer时会出现如下异常:
java.rmi.ServerException: RemoteException occurred in server thread; nested exception is:
java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is:
java.lang.ClassNotFoundException: org.rmi.HelloImplement_Stub
解决办法:测试时将oracle 、Webogic 等设置的JDK环境变量先删除。然后再启动服务 java HelloServer;出现这个问题归根结底还是环境变量的设置问题。
***如果你是在本机进行测试,下面两段代码需要注意:
Hello h = (Hello)Naming.lookup("rmi://10.40.12.18/HelloService");
Naming.rebind("rmi://10.40.12.18.:1099/HelloService", hImpl);
默认端口为1099, 本机测试,不能使用localhost作为IP地址,使用机器名将能够正确在本机运行:
Hello h = (Hello)Naming.lookup("rmi://你的机器名/HelloService");
Naming.rebind("rmi://你的机器名.:1099/HelloService", hImpl);