我想在Java Swing客戶端和Tomcat服務器之間實現RMI工作流。我遇到的困難是創建插件體系結構,以便購買我們產品的用戶可以將新的jar文件放到服務器上的插件文件夾中,然後讓這些類可用於客戶端和服務器。如何使用RMI實現插件體系結構?
現在,我有客戶端部分工作:它向服務器請求插件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'私有靜態變量,但它是最終的,所以我假設我不能設置一個新的值(還沒有實際測試過)。
- 這裏[UPDATE從服務器顯示堆棧跟蹤]是通過在客戶端嘗試使用該插件的一個類在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
儘管我完全不瞭解這個問題,但是對於運行時的jar/plugin管理,你有沒有給OSGi一個想法? – happybuddha
不,我完全不知道OSGi –