java - RMI(JDK 1.6): ClassNotFoundException for <server>_Stub in client-app

标签 java rmi classnotfoundexception

经过两天的谷歌搜索、stackoverflow-ing以及在其他论坛寻找答案,我终于放弃了,希望能在这里找到答案!

在运行一个简单的 RMI 客户端-服务器应用程序时,我遇到了一个恼人的问题,尽管它似乎(或者也许我只是遗漏了一点点)是 RMI 的一个众所周知的问题。

我正在使用 Eclipse 和 m2eclipse(Maven 集成)进行依赖项管理。我的项目结构如下: - client:客户端代码,对共享的依赖 - 服务器:服务器代码,对共享的依赖 - 共享:服务器和客户端之间的远程接口(interface)和共享类 - Integrationtest:测试项目,同时依赖于客户端和服务器

共享:

客户端可以调用的远程接口(interface)是:

public interface IServerReceiver extends Remote, Serializable {
  void connect(long clientId) throws RemoteException;
}

此接口(interface)位于客户端和服务器都依赖的共享项目中,因此它位于客户端的类路径中

服务器端:

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() 方法返回预期结果。

但是,当我尝试正常启动服务器实例,然后启动尝试 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)

在寻找答案时,最突出的是:客户端必须有权访问服务器接口(interface)定义(IServerReceiver)。然而,对我来说,情况似乎就是这样,因为适当的依赖关系已经就位(客户端->共享,服务器->共享,IServerReceiver 位于共享中)。 我不太明白的异常的另一个方面是:从 JDK 1.5 开始,不再需要通过 rmic 生成 stub ,而是通过动态代理来实现。因此,客户端只需访问 IServerReceiver 接口(interface)即可创建动态代理。那么他为什么会提示根本找不到 ServerReceiver_Stub 类呢?

由于集成测试成功运行,并且在该测试中客户端还可以访问 IServerReceiver 接口(interface)的实现,我是否正确地假设客户端不仅需要访问远程接口(interface),而且还需要访问远程接口(interface)?还有它的实现吗?

我现在很困惑,所以也许你可以帮我解释一下这个问题?感谢您阅读这么长的帖子! ;-)

干杯, 克里斯

最佳答案

我同意,您不需要 stub ,因为您在导出对象时提供了端口号。唯一的解释是绑定(bind)的是生成的 stub 而不是动态 stub 。我会删除任何存在的 stub 文件并重新测试。如果服务器需要 stub 但没有 stub ,那么它应该在导出时失败,而不是在有人查找它时失败。

Am I right in assuming that the client needs not only access to the remote interface but also its implementation?

没有。它只需要 stub 。实现是远程的。这就是整个想法。但它也需要 stub 依赖的任何类,即远程接口(interface)和它依赖的任何类,依此类推,直到关闭。

我还有一些问题:

  1. 为什么要向新的 ServerReceiver(rmiRegistryPort) 提供注册表端口?
  2. 我认为 ServerReceiver 不会扩展 UnicastRemoteObject?
  3. 您确定这是正在执行的真实服务器代码吗?

关于java - RMI(JDK 1.6): ClassNotFoundException for <server>_Stub in client-app,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6025406/

相关文章:

java - 将日期和时间合并到时间戳中

java - 用Java猜数字程序

java - 在 Android 中序列化一个 Intent ?

java - 如何强制或预测jstatd的第二个开放端口?

Java RMI -registry.bind 是否阻塞以及服务器如何知道客户端是否已关闭

java - Python 用于运行 Java JAR,ClassNotFoundException

java - 使用 DB2 的 JDBC 驱动程序时出现 ClassNotFoundException

Java/Regex - 查找字符串中任意位置的字符

java - RMI 何时建立 TCP 连接?

当不在 Web 服务器中运行时,库中的 Java 重载方法失败