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是否正确加载,但是当我尝试调用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; } 

它一直在说关于禁用类加载的东西,所以我猜问题就在那里…谢谢!

远程类加载可能很棘手。

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

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

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

每次在RMI动态代理上调用方法时, MarshalInputStream (扩展ObjectInputStream以覆盖resolveClassresolveProxyClass )都会委托LoaderHandler查找3个位置供ClassLoader使用:

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

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

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

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

您需要服务器端的安全管理器,而不仅仅是客户端。

没有这个,服务器的RMI引擎拒绝从客户端加载类,因为它不能保证这些不会在服务器上做坏事。

你需要加载RMI类吗? 服务器是否已经拥有客户端尝试发送的类?

我知道为什么会这样。 例如,您在项目A中启动服务器,但是您使用项目B中的客户端来请求此服务器,这是错误的。 所以你应该将服务器和客户端放在同一个项目中。