1

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」プライベート静的変数に設定するリフレクションとブルートフォースを使用することを考えましたが、それは最終的なものであるため、それに新しい値を設定できないと思います (実際にはテストしていません) )。

[更新 - サーバーからのスタック トレースを表示] 以下は、クライアントがサーバーへの RMI 呼び出しでプラグイン クラスの 1 つを使用しようとしたときにサーバーによって生成されるスタック トレースです。

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
4

2 に答える 2

0

答えが見つかりました!サーバーのシステム プロパティ 'java.rmi.server.useCodebaseOnly' が true に設定されていました (私が使用している Java 6 では false であると文書化されているため、これは奇妙です)。これが true の場合、サーバーは、クライアントからのクラス アノテーションに埋め込まれたクラスパス URL を無視します。false に設定すると、サーバーはクライアントから注釈を読み取り、クラスを解決しています!

于 2013-06-19T12:15:50.947 に答える