gpt4 book ai didi

java - 如何使用 RMI 实现插件架构?

转载 作者:行者123 更新时间:2023-11-28 22:21:21 25 4
gpt4 key购买 nike

我正在尝试在 Java Swing 客户端和 Tomcat 服务器之间实现 RMI 工作流。我遇到的困难是创建插件架构,以便购买我们产品的用户可以将新的 jar 文件放入服务器上的插件文件夹中,然后让客户端和客户端都可以使用这些类服务器。

现在,我的客户端部分正在工作:它向服务器请求插件 URL 列表,服务器扫描插件文件夹并返回与它在其中找到的 jar 文件相对应的 URL,然后客户端使用网络类加载器与那些提供的 URL 动态加载插件类。

当客户端通过使用插件类的 RMI 将对象发送到服务器时,就会出现问题。服务器在其类路径中没有这些类(因为它们只是放在硬盘驱动器上的文件夹中,而不是在 webapp 或 Tomcat 文件夹中),因此它会抛出错误。我需要为此找到解决方案。

有一些限制需要注意:

  • 我们不希望用户在将新插件放入服务器上的插件文件夹时必须重新启动 Tomcat。

  • 我们不想更改有关 Tomcat 安装本身的任何内容,例如启动参数或其他 jar 文件,因为我们的解决方案需要由已经在运行自己的 Tomcat 的客户安装。他们只是想将我们的产品放到他们的 webapp 目录中然后走。

以下是我尝试过但没有奏效的一些潜在解决方案:

  • 我无法使用服务器上的“java.rmi.server.codebase”系统属性来解决这个问题,因为插件 jar 列表在运行时会发生变化,而这个属性在启动时被缓存。我还希望不必安装 SecurityManager,这是此方法所必需的。

  • 定义我们自己的类加载器并设置“java.rmi.server.RMIClassLoaderSpi”系统属性看起来正是我们所需要的,但是在使用该方法时,类加载器需要由系统类加载器加载。由于我们在使用 WebAppClassLoaders 的 Tomcat 中运行,因此无法正常工作。

  • 我考虑过使用反射和暴力将我们的自定义类加载器设置到 RMIClassLoader 类中的“defaultProvider”私有(private)静态变量中,但它是最终的,所以我假设我无法为其设置新值(还没有实际测试过)。

[更新 - 显示来自服务器的堆栈跟踪]这是当客户端尝试在对服务器的 RMI 调用中使用其中一个插件类时服务器生成的堆栈跟踪:

Jun 19, 2013 7:20:58 AM sun.rmi.server.UnicastServerRef logCallException
FINE: RMI TCP Connection(4)-192.168.1.107: [192.168.1.107] exception:
java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is:
java.lang.ClassNotFoundException: com.prosc.cps.CPSProperties
at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:294)
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:895)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
at java.lang.Thread.run(Thread.java:680)
Caused by: java.lang.ClassNotFoundException: com.prosc.cps.CPSProperties
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:249)
at sun.rmi.server.LoaderHandler.loadClass(LoaderHandler.java:432)
at sun.rmi.server.LoaderHandler.loadClass(LoaderHandler.java:163)
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:201)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1589)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1494)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1748)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1327)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:349)
at sun.rmi.server.UnicastRef.unmarshalValue(UnicastRef.java:306)
at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:288)
... 9 more

最佳答案

在客户端使用 RMIClassLoaderSPI 方法。这相当于在客户端动态设置代码库属性:类在通过 RMI 发送到服务器时得到注释,因此服务器可以加载它们。 p>

关于java - 如何使用 RMI 实现插件架构?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17171978/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com