【问题标题】:RMI binding fails with "java.lang.ClassNotFoundException: rmitest.IRemote"RMI 绑定失败并出现“java.lang.ClassNotFoundException: rmtest.IRemote”
【发布时间】:2017-01-26 12:59:14
【问题描述】:

我在将远程对象绑定到 RMI 注册表时遇到问题。我已将我的代码简化为一个非常简单的示例,当我在我的计算机(Windows 10)上测试它时可以正常工作。但是如果我在另一台计算机(Windows 7)上启动它,当registry.bind(id, remoteObject); 被调用时,我会得到这个异常:

java.lang.ClassNotFoundException: 
rmitest.IRemote (no security manager: RMI class loader disabled)

我不需要 SecurityManager,因为所有类文件都在 jar 中,我不想使用动态代码加载功能。

为什么它会尝试加载安全管理器,为什么即使我定义了它也找不到?它可以在一台机器上运行但不能在另一台机器上运行的原因可能是什么?我认为代码是好的,它必须是一些配置问题,但我不确定究竟是什么配置错误。

这里是远程接口和远程对象实现,我在 Eclipse 中导出为可运行 Jar 为 rmitest.jar

public interface IRemote extends Remote {
    void foo() throws RemoteException;
}
public class RemoteImpl extends UnicastRemoteObject implements IRemote {

    private static Registry     registry;

    public RemoteImpl() throws RemoteException {
        super();
    }

    public static void main(final String[] args) throws Exception {
        try {
            LocateRegistry.createRegistry(Registry.REGISTRY_PORT);
        } catch (final Exception e) {
            // already created
        }
        registry = LocateRegistry.getRegistry(Registry.REGISTRY_PORT);
        registry.bind(UUID.randomUUID().toString(), new RemoteImpl());
        System.out.println("Binding successful");
    }

    @Override
    public void foo() throws RemoteException {
        System.out.println("foo");
    }
}

这是完整的堆栈跟踪,它在调用registry.bind 的行中抛出,并且在使用以下任一命令运行时完全相同: java -jar rmitest.jar
java -Djava.security.manager -Djava.security.policy=policy -jar rmitest.jar

很奇怪,显然在这两种情况下都需要安全管理器,但即使在第二种情况下也找不到安全管理器。

Exception in thread "main" java.rmi.ServerException: RemoteException occurred in server thread; nested exception is: 
    java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is: 
    java.lang.ClassNotFoundException: rmitest.IRemote (no security manager: RMI class loader disabled)
    at sun.rmi.server.UnicastServerRef.oldDispatch(Unknown Source)
    at sun.rmi.server.UnicastServerRef.dispatch(Unknown Source)
    at sun.rmi.transport.Transport$1.run(Unknown Source)
    at sun.rmi.transport.Transport$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.Transport.serviceCall(Unknown Source)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$256(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
    at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:276)
    at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:253)
    at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:379)
    at sun.rmi.registry.RegistryImpl_Stub.bind(Unknown Source)
    at rmitest.RemoteImpl.main(RemoteImpl.java:29)
Caused by: java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is: 
    java.lang.ClassNotFoundException: rmitest.IRemote (no security manager: RMI class loader disabled)
    at sun.rmi.registry.RegistryImpl_Skel.dispatch(Unknown Source)
    at sun.rmi.server.UnicastServerRef.oldDispatch(Unknown Source)
    at sun.rmi.server.UnicastServerRef.dispatch(Unknown Source)
    at sun.rmi.transport.Transport$1.run(Unknown Source)
    at sun.rmi.transport.Transport$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.Transport.serviceCall(Unknown Source)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$256(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.ClassNotFoundException: rmitest.IRemote (no security manager: RMI class loader disabled)
    at sun.rmi.server.LoaderHandler.loadProxyClass(Unknown Source)
    at java.rmi.server.RMIClassLoader$2.loadProxyClass(Unknown Source)
    at java.rmi.server.RMIClassLoader.loadProxyClass(Unknown Source)
    at sun.rmi.server.MarshalInputStream.resolveProxyClass(Unknown Source)
    at java.io.ObjectInputStream.readProxyDesc(Unknown Source)
    at java.io.ObjectInputStream.readClassDesc(Unknown Source)
    at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
    at java.io.ObjectInputStream.readObject0(Unknown Source)
    at java.io.ObjectInputStream.readObject(Unknown Source)
    ... 15 more

这是策略文件,它应该允许一切:

grant {
  permission java.security.AllPermission;
};

【问题讨论】:

  • “尝试加载安全管理器”,这里没有其他建议。它尝试加载您的 class,但没有找到它。不要妄下结论。
  • @EJP 我的意思是“期望安全管理器存在”,因为我将异常消息解释为表明缺少安全管理器是无法加载类的原因.
  • 嗯,这并不意味着这些事情中的任何一个。 注意 安全管理器没有运行。不是原因。
  • 而你失败的是ClassNotFoundException: rmitest.IRemote

标签: java rmi


【解决方案1】:

问题在于“其他 Java 进程”提供了自己的注册表,它无法访问您的 CLASSPATH。你会发现,如果你有比createRegistry() 的空catch 块更好的东西。

【讨论】:

  • 是的,一个空的 catch 块是我不应该做的暴行——但我复制了这个问题并记录了异常,它总是完全相同 java.net.BindException: Address already in use: JVM_Bind,无论注册表是否有权访问到类路径与否。
  • 无论如何,如果我不能确定另一个应用程序尚未在该端口创建注册表,我应该避免在默认端口使用createRegistry
  • 您的第一条评论没有意义。 BindException 表示已经在另一个 JVM 中运行了另一个 Registry,而随后的 ClassNotFoundException 表示该 Registry 没有与您的 JVM 相同的 CLASSPATH。如果你没有得到BindException,你也不会得到ClassNotFoundException
  • 抱歉,我误解了关于空捕获的评论,并认为您的意思是异常告诉我注册表是否具有不同的类路径。问题是,我的应用程序必须同时在同一主机上的多个进程中运行(每个进程在不同的用户帐户下运行以与旧系统交互),所以我希望大多数时间都会抛出异常,这就是为什么我没注意它。在这个(公认的 hacky)设置中,我得到(并忽略)了 BindException,因为我假设另一个具有相同类路径的进程创建了注册表。感谢您清理一切。
【解决方案2】:

问题是其他一些正在运行的 Java 进程似乎干扰了注册表绑定。我不知道这个流氓进程到底做了什么,但杀死它解决了错误。不需要安全管理器,现在只需像往常一样运行 jar。

【讨论】:

    猜你喜欢
    • 2017-10-09
    • 1970-01-01
    • 1970-01-01
    • 2023-03-25
    • 2011-06-15
    • 1970-01-01
    • 2021-08-03
    相关资源
    最近更新 更多