经过2天的谷歌搜索,stackoverflow-ing并在其他论坛中寻找答案,我终于放弃了,希望在这里找到答案!
我在运行一个简单的 RMI 客户端-服务器应用程序时遇到了一个烦人的问题,尽管它似乎(或者我只是遗漏了一点点)是 RMI 的一个众所周知的问题。
我正在使用 Eclipse 和 m2eclipse(Maven 集成)进行依赖管理。我的项目结构如下: - 客户端:客户端代码,对共享的依赖 - 服务器:服务器代码,对共享的依赖 - 共享:服务器和客户端之间的远程接口和共享类 - 集成测试:测试项目,同时依赖于客户端和服务器
共享:
客户端可以调用的远程接口是:
public interface IServerReceiver extends Remote, Serializable {
void connect(long clientId) throws RemoteException;
}
该接口位于客户端和服务器都依赖的共享项目中,因此它位于客户端的类路径中。
服务器端:
Server 类负责创建注册表并导出远程对象(ServerReceiver 实现 IServerReceiver):
registry = LocateRegistry.createRegistry(rmiRegistryPort);
serverReceiver = new ServerReceiver(rmiRegistryPort);
registry.rebind(IConstants.RMI_SERVER_RECEIVER_ID, UnicastRemoteObject.exportObject(serverReceiver, 0));
启动服务器时,通过定义 -Djava.security.policy 向服务器的 JVM 提供一个安全策略文件(尽管我认为这与这里描述的问题无关)。
客户端
负责将客户端连接到服务器的类是 ServerConnector 类:
...
public ServerConnector() {
...
registry = LocateRegistry.getRegistry(serverRMIHost, serverRMIPort);
serverReceiver = (IServerReceiver) registry.lookup(IConstants.RMI_SERVER_RECEIVER_ID);
serverReceiver.connect(client.getId());
...
}
Client 类的构造函数如下所示(省略了一些行):
public Client(..) {
....
serverConnector = new ServerConnector(serverRMIHost, serverRMIPort, this);
....
}
除了服务器,客户端还获得了一个安全策略文件。
测试
当我启动集成测试创建服务器然后创建客户端时:一切都按预期正常工作,并且 connect() 方法返回预期结果。
但是,当我尝试正常启动服务器实例,然后启动尝试连接()到服务器的客户端实例时,会抛出以下异常:
Caused by: java.rmi.UnmarshalException: error unmarshalling return; nested exception is:
java.lang.ClassNotFoundException: assign2.comm.ServerReceiver_Stub
at sun.rmi.registry.RegistryImpl_Stub.lookup(Unknown Source)
at assign2.comm.ServerConnector.<init>(ServerConnector.java:65)
在寻找答案时,最突出的是:客户端必须有权访问服务器接口定义(IServerReceiver)。但是,对我来说,情况似乎就是这样,因为适当的依赖关系已经到位(客户端->共享,服务器->共享,IServerReceiver 位于共享中)。我不太了解的异常的另一个方面是:从 JDK 1.5 开始,不再需要通过 rmic 生成存根,而是通过动态代理来实现。因此,客户端只需访问接口 IServerReceiver 即可创建动态代理。为什么他会抱怨根本找不到 ServerReceiver_Stub 类呢?
由于集成测试成功运行并且在该测试中客户端还可以访问 IServerReceiver 接口的实现,我是否正确假设客户端不仅需要访问远程接口,还需要它的实现?
我现在很困惑,所以也许你能帮我解释一下这个问题?感谢您阅读了那么长的帖子!;-)
干杯,克里斯