问题描述
|
嗨,我有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();
}
}
服务器已正确加载,但是当我尝试调用ѭ1时,出现以下错误:
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;
}
它一直在说关于禁用类加载的东西,所以我想问题就在那儿……
谢谢!
解决方法
远程类加载可能很棘手。
原始帖子不包含有关代码库的任何信息。可能是客户端的安全配置正确,但是无法访问远程代码。客户端直接从“代码库”中加载类。服务不会通过RMI连接将它们提供给客户端。该服务仅引用类的外部源。
服务器应指定系统属性“ 4”。该值必须是客户端可访问的URL,可以从中加载必需的类。如果这是“ 5” URL,则客户端必须可以访问文件系统。
反之亦然:如果服务器应该能够从客户端加载类(如此处所示),则客户端必须将代码库属性设置为服务器可访问的URL。
, 每次在RMI动态代理上调用方法时,
MarshalInputStream
(扩展ObjectInputStream
以覆盖resolveClass
和resolveProxyClass
)都会将其委托给LoaderHandler
,以便在3个地方查找供ClassLoader
使用:
正在被调用的代理的ClassLoader(从技术上讲,它使用一种称为latestUserDefinedLoader()
的hack:在栈上移动,在栈上查找不属于JRE的第一个方法)。
调用者的线程本地contextClassLoader
代码库ClassLoader(如果启用了SecurityManager)
如果系统属性为“ 14”,则代码库ClassLoader使用远程“ 4”中的URL。请注意,在JDK 7u21中,useCodebaseOnly的默认值已更改,因此除非您进行更改,否则不再使用远程代码库!
否则,代码库ClassLoader使用本地“ 4”中的URL。
因此,有几种可能的原因,在调用Remote方法时会出现ClassNotFoundException
的信息:
如果堆栈中包含“没有安全管理器:RMI类加载器已禁用”,则如果需要双方都进行远程类加载以获取所有远程接口和可序列化的类,请确保按其他说明设置SecurityManager。
如果您正在使用远程类加载,并且在升级到JRE 7u21后它停止工作,则可以将-Djava.rmi.server.useCodebaseOnly=true
设置为与以前的行为相匹配,或者将-Djava.rmi.server.codebase
设置为在本地和远程侧以空格分隔的URL列表。并确保计算机可以访问这些URL。
如果您在本地使用其父类加载器定义了一些Remote接口的自定义ClassLoader,则请确保调用ѭ20,以便RMI将使用该ClassLoader。 (这是我的问题:我有一个SwingWorker
碰巧被安排到在EventDispatchThread上设置contextClassLoader之前创建的工作线程上)。例如,A和C属于您的自定义ClassLoader,而B属于父ClassLoader,则当您调用a.getB()。getC()时,getB()调用将使用自定义类加载器,但getC()调用将无法在LatestUserDefinedClassLoader中找到C,并且必须回退到contextClassLoader。
所有这些都是关于ObjectInputStream API设计不佳的警告。 ObjectInputStream应该要求您传递ClassLoader参数,而不是尝试使用LatestUserDefinedLoader,contextClassLoader和代码库随意找到一个参数。
, 您不仅需要在客户端,还需要在服务器端使用安全管理器。
没有这个,服务器的RMI引擎将拒绝从客户端加载类,因为它不能保证它们不会在服务器上做坏事。
您是否完全需要加载RMI类?服务器是否已经具有客户端尝试发送的类?
,我想添加一些可能对某些人特别是初学者有用的东西。
我是来这里寻找上述错误的解决方案的,但是作为一个初学者,我不知道如何使用安全策略并指定\“ java.rmi.server.codebase \”属性。
解决此错误的最简单方法是确保要通过RMI发送的对象的类位于包的相同路径中。通过这种方式,两个应用程序相对于其主文件夹和文件夹在同一位置具有该类。错误将解决。
例:
如果要从服务器向客户端发送“ 22”类型(可序列化)的对象,请确保该对象位于同一包路径中。
在我的情况下,在服务器应用程序中,对象位于ѭ23in中,而在客户端应用程序中,对象位于com.example.springdemo.service.dto
中。问题是,使用IntelliJ,因为service
软件包中什么都没有,而是另一个软件包,它们的名称被连接起来(service.dto
),我看不到路径不一样。
因此,请确保您的类具有相同的包路径。 (对于我的情况,解决方案:application22ѭ类必须同时在包装中使用:com.example.springdemo.dto
。
我知道这不是最好的解决方案,但这只是一个“小技巧”,但是那时我会很高兴找到这个解决方案,因为它使我免于浪费大量时间来解决问题。
我希望这对希望快速解决该错误的人有所帮助,因为我认为学习使用安全管理器并包括代码库可能会有些棘手,并且需要时间。
, 我知道为什么会这样。
例如,您在项目A中启动服务器,
但是您在项目B中使用客户端来请求此服务器,这是错误的。
因此,您应该将服务器和客户端放在同一项目中。