运行RMI服务器时,出现ClassNotFound错误。

29

您好,我正在尝试运行一个将类绑定到命名服务器的Java应用程序,但是我一直收到ClassNotFoundException的错误。

首先,我启动注册表:

rmiregistry

然后从Eclipse中尝试执行服务器,但出现以下错误:

java.rmi.ServerException:服务器线程中发生RemoteException;嵌套异常是: java.rmi.UnmarshalException:错误取消编组参数;嵌套异常是: java.lang.ClassNotFoundException:progInternet2008.commons.NominabileFactory at sun.rmi.server.UnicastServerRef.oldDispatch(UnicastServerRef.java:396) at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:250) at sun.rmi.transport.Transport $ 1.run(Transport.java:159) at java.security.AccessController.doPrivileged(Native Method) at sun.rmi.transport.Transport.serviceCall(Transport.java:155) at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:535) at sun.rmi.transport.tcp.TCPTransport $ ConnectionHandler.run0(TCPTransport.java:790) at sun.rmi.transport.tcp.TCPTransport $ ConnectionHandler.run(TCPTransport.java:649) at java.util.concurrent.ThreadPoolExecutor $ Worker.runTask(ThreadPoolExecutor.java:886) at java.util.concurrent.ThreadPoolExecutor $ Worker.run(ThreadPoolExecutor.java:908) at java.lang.Thread.run(Thread.java:619) at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:255) at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:233) at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:359) at sun.rmi.registry.RegistryImpl_Stub.rebind(Unknown Source) at progInternet2008.Pozzobon.tesi.Slave.main(Slave.java:54) Caused by: java.rmi.UnmarshalException:错误取消编组参数;嵌套异常是: java.lang.ClassNotFoundException:progInternet2008.commons.NominabileFactory at sun.rmi.registry.RegistryImpl_Skel.dispatch(Unknown Source) at sun.rmi.server.UnicastServerRef.oldDispatch(UnicastServerRef.java:386) at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:250)

在"sun.rmi.transport.Transport$1.run(Transport.java:159)"处发生异常。 在"java.security.AccessController.doPrivileged(Native Method)"执行特权代码。 "sun.rmi.transport.Transport.serviceCall(Transport.java:155)"调用RMI服务。 "sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:535)"处理TCP传输中的消息。 "sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:790)"运行TCP连接的处理程序。 "sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:649)"运行TCP连接的处理程序。 "java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)"运行线程池工人任务。 "java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)"运行线程池工人。 "java.lang.Thread.run(Thread.java:619)"运行线程。 由于找不到 "progInternet2008.commons.NominabileFactory"类,抛出"java.lang.ClassNotFoundException"异常。 在"java.net.URLClassLoader.findClass(URLClassLoader.java:188)"中查找类。 通过反射加载了代理接口,但找不到类,因此无法解析代理类。作为 VM 参数,我设置了以下内容:

-Djava.rmi.server.codebase=file:${workspace_loc}/progInternet2008

请帮助我。 (我正在使用 Java 6)

你最后解决了这个问题吗? - Nathan Feger
一个文件:codebase URL 只有在客户端和服务器在同一台机器上时才能工作,此时您根本不需要 codebase 功能,或者当它引用一个从客户端和服务器看起来相同的共享驱动器时,这意味着一个局域网,在这种情况下,是否需要该功能是值得怀疑的。 - user207421
9个回答

74

从您的 /bin、/build 或 /build/classes 文件夹中选择根目录,运行 rmiregisrty 命令。

我花了半天时间尝试解决同样的问题。


3
非常感谢!它只适用于最简单的运行(仅限本地)。 - Misiek
3
你救了25个人! - Jalal Sordo
2
谢谢,这是我需要的答案!我更进一步,并在我的代码中使用命令LocateRegistry.createRegistry(1099)启动了注册表。 - lolynns
你是怎么发现的? - Minh Nghĩa
1
@lolynns 你值得一枚奖章 - Gilbert
1
对于IntelliJ用户来说,文件夹是out/production/myrmi。那个包含.class文件的文件夹。 - Gilbert

27
异常发生的原因是rmiregistry应用程序不知道从哪里加载类。当您尝试将对象绑定到RMI注册表时,注册表会下载该对象的类定义。其他一些答案告诉您通过为rmiregistry应用程序设置类路径来解决此问题,以便在启动时具有类定义,并且不需要下载任何内容,但Sun的Java RMI教程明确表示不要这样做。我怀疑这可能会在注册表中的类版本和服务器上的类之间引起冲突。
处理问题的正确方法是像您尝试的那样设置java.rmi.server.codebase属性。该属性要求目录路径以正斜杠结尾,如下所示:
-Djava.rmi.server.codebase=file:${workspace_loc}/progInternet2008/

如果${workspace_loc}变量是相对路径,并且rmiregistry应用程序未在相同目录中启动,因此相对路径对其不正确,则您可能也会遇到问题。 如果您将路径设置为绝对路径,或在适当的目录中启动rmiregistry,则ClassNotFoundException应该消失。 有关更详细的信息,请参见java.rmi.server.codebase属性的教程


教程只是在说,因为它使用了代码库功能,所以它破坏了代码库功能。否则这不是一个问题。 - user207421

7

好的,我刚刚解决了这个问题。请确保在运行rmiregistry命令时设置了CLASSPATH环境变量。

例如,您可能有一个脚本:

set CLASSPATH=[path to jdbc driver].jar
rmiregistry.exe

这就是我需要让我的丢失的类路径重新工作的全部内容。我不确定如何将-cp命令行发送到rmiregistry.exe。它的文档相当缺乏。

4
Sun的RMI教程明确告诉你不要这样做,它可能会引起问题。 - A. Levy
@A.Levy 他们确切地在哪里说了那个?唯一可能会导致问题的方式是如果正在使用代码库功能。 - user207421
2
点赞。这是过去10个问题中唯一有效的修复方法。useCodeBaseOnly=false不起作用。设置所有权限的-Djava.security.policy=file也不起作用。正如其他人所指出的那样,-Djava.rmi.server.codebase=some.jar也不起作用... - Rui Botelho

5

我相当确信,您必须使用与应用程序相同的类路径启动RMI服务器。 我相信它采用与Java相同的参数,即 -cp [您的类路径]


当您说RMI服务器时,是指rmiregistry应用程序还是应用程序的服务器组件与客户端组件? - simgineer

3

关闭rmiregistry最初启动的cmd窗口。在新的cmd中,转到您的项目类文件所在的位置(直到bin),并使用以下命令启动注册表:

rmiregistry -J-Djava.rmi.server.useCodebaseOnly=false

如果您正在使用Eclipse,请运行ServerSideProject,您的ImplementationClass实例将绑定到指定的URL。

只需在绑定方法下面打印一行,然后查看它是否被打印出来。如果成功打印,则表示服务器正常工作。


2

2

我曾经遇到过同样的问题,为了解决这个问题,确保在运行rmiregistry时,CLASSPATH设置为包含服务器类的路径。

在Linux机器上运行以下命令:

export CLASSPATH="<server_class_path>"

请确保已设置CLASSPATH

echo $CLASSPATH

设置类路径后,运行 rmiregistry 命令。

rmiregistry &

2

尝试在您的VM参数末尾添加/bin:

-Djava.rmi.server.codebase=file:${workspace_loc}/progInternet2008/bin

您需要运行的文件在此目录中,因此您需要将其包含在路径中。


1
关于类文件是否在bin目录中的问题,没有证据支持。 - user207421

1
我花了一整天的时间卸载和重新安装我的JDK,并更改类路径和环境变量。但罪魁祸首是命令start rmigregistry没有以正确的方式启动rmiregistry。因此,感谢这个页面上的评论,解决方案是暂时取消设置CLASSPATH。这可以通过命令set CLASSPATH=完成。

1
不以“正确的方式”启动它,使用“你的”CLASSPATH,因为它事先无法知道。把这个做好是你的责任。不要责怪工具。 - user207421

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接