Java:没有安全管理器:RMI 类装入器被禁用

嗨,我有RMI应用程序,现在我尝试从我的客户端调用服务器上的一些方法。我有以下代码:

public static void main(final String[] args) {
    try {
        //Setting the security manager

        System.setSecurityManager(new RMISecurityManager());
        IndicatorsService server = (IndicatorsService) Naming
                .lookup("rmi://localhost/" + IndicatorsService.SERVICE_NAME);
        DataProvider provider = new OHLCProvider(server);
        server.registerOHLCProvider(provider);
    } catch (MalformedURLException e) {
        e.printStackTrace();
    } catch (RemoteException e) {
        e.printStackTrace();
    } catch (NotBoundException e) {
        e.printStackTrace();
    }
}

服务器已正确加载,但当我尝试调用时,我收到以下错误:server.registerOHLCProvider(provider);

     java.rmi.ServerException: RemoteException occurred in server thread; nested exception is: 
    java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is: 
    java.lang.ClassNotFoundException: sk.xorty.client.providers.OHLCProvider (no security manager: RMI class loader disabled)
    at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:336)
    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:662)
    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:142)
    at sk.fri.statistics.service.impl.IndicatorsServiceImpl_Stub.registerOHLCProvider(Unknown Source)
    at sk.fri.statistics.service.Client.main(Client.java:61)
Caused by: java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is: 
    java.lang.ClassNotFoundException: sk.xorty.client.providers.OHLCProvider (no security manager: RMI class loader disabled)
    at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:296)
    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:662)
Caused by: java.lang.ClassNotFoundException: sk.xorty.client.providers.OHLCProvider (no security manager: RMI class loader disabled)
    at sun.rmi.server.LoaderHandler.loadClass(LoaderHandler.java:375)
    at sun.rmi.server.LoaderHandler.loadClass(LoaderHandler.java:165)
    at java.rmi.server.RMIClassLoader$2.loadClass(RMIClassLoader.java:620)
    at java.rmi.server.RMIClassLoader.loadClass(RMIClassLoader.java:247)
    at sun.rmi.server.MarshalInputStream.resolveClass(MarshalInputStream.java:197)
    at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1574)
    at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1495)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1731)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1328)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:350)
    at sun.rmi.server.UnicastRef.unmarshalValue(UnicastRef.java:306)
    at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:290)
    ... 9 more

我已将我的策略文件添加为VM参数,如下所示:

grant {
    permission java.security.AllPermission;
}

它一直在说一些关于禁用类加载的东西,所以我想问题出在某个地方......谢谢!


答案 1

远程类加载可能很棘手。

原始帖子不包含有关代码库的任何信息。可能是客户端的安全配置正确,但它无法访问远程代码。这些类由客户端直接从“代码库”加载。服务不会通过 RMI 连接向客户端提供它们。该服务仅引用类的外部源。

服务器应指定系统属性 。该值必须是客户端可访问的 URL,可以从中加载必要的类。如果这是一个 URL,则客户端必须可以访问文件系统。java.rmi.server.codebasefile:

反之亦然:如果服务器应该能够从客户端加载类(如此处所示),则客户端必须将代码库属性设置为服务器可访问的 URL。


答案 2

每次调用 RMI 动态代理上的方法时,MarshalInputStream(扩展 ObjectInputStream 以覆盖 和 )委托 LoaderHandler 在 3 个位置查找要使用的方法:resolveClassresolveProxyClassClassLoader

  1. 正在调用的代理的 ClassLoader(从技术上讲,它使用了一个名为 :的 hack,它沿着堆栈向上移动,在堆栈上查找不属于 JRE 的第一个方法)。latestUserDefinedLoader()
  2. 调用方的线程本地contextClassLoader
  3. 代码库类加载器(如果启用了 SecurityManager)
    1. 如果 System 属性 ,则代码库 ClassLoader 使用远程中的 URL。请注意,useCodebaseOnly 的默认值在 JDK 7u21 中已更改,因此除非您更改它,否则不再使用远程代码库java.rmi.server.useCodebaseOnly=falsejava.rmi.server.codebase
    2. 否则,代码库 ClassLoader 使用本地 中的 URL。java.rmi.server.codebase

因此,在调用 Remote 方法时,有几个可能的原因:ClassNotFoundException

  • 如果堆栈包含“无安全管理器:RMI 类装入器已禁用”,那么如果您需要为双方加载远程类以获取所有远程接口和可序列化的类,请确保按照其他人的描述设置 SecurityManager。
  • 如果您使用的是远程类装入,并且在升级到 JRE 7u21 时它停止工作,那么要么设置为与以前的行为匹配,要么设置为本地端和远程端的 URL 列表以空格分隔。并确保计算机可以访问这些URL。-Djava.rmi.server.useCodebaseOnly=true-Djava.rmi.server.codebase
  • 如果在本地使用自定义类加载器,其父类加载器定义了一些远程接口,请确保调用,以便 RMI 将使用该类加载器。(这是我的问题:我有一个碰巧被调度到一个工作线程上,该线程是在 EventDispatchThread 上设置上下文ClassLoader之前创建的)。例如,A 和 C 属于您的自定义 ClassLoader,但 B 属于父 ClassLoader,然后当您调用 a.getB().getC() 时,getB() 调用将使用自定义类装入器,但 getC() 调用将无法在最新的UserDefinedClassLoader 中找到 C,并且必须回退到上下文ClassLoader。Thread.setContextClassLoader(ClassLoader)SwingWorker

所有这些都是对ObjectInputStream糟糕的API设计的警示。ObjectInputStream 应该要求您传递一个 ClassLoader 参数,而不是尝试使用 latestUserDefinedLoader、contextClassLoader 和 codebase 随意查找一个参数。


推荐