環境
これは Java RMI を使用するアプリケーションで、次のものがあります。
- ホスト A 上のクライアントとホスト B 上のサーバー。
- ホスト A 上の HTTP サーバー。クライアントとサーバーが使用するすべてのクラスのコピーを保持します。
- RMI レジストリはサーバー コードから作成され、サーバー JVM と CLASSPATH を共有します。
サーバーおよびクライアント アプリケーションの場合:
java.rmi.server.codebaseプロパティは (コード内で) HTTP サーバーの URL に設定されます。- 適切なポリシーを備えたセキュリティ マネージャーが配置されています。
- は
java.rmi.server.hostnameLAN アドレスに設定されます。
メソッド呼び出し:
- サーバー メソッドは、型
WorkRequest(抽象クラス) のパラメーターで定義されます。 - クライアントは、サブクラスを使用してこのメソッドを呼び出します
WorkRequestSquare。 WorkRequestSquareサーバーコードでは決して言及されていません
サーバーコード
Object execute(WorkRequest work) throws RemoteException { return work.execute(); }
クライアントコード:
try { servant.execute(new WorkRequestSquare(123)); }
catch (RemoteException e) {
System.out.println("Error while submitting work request:");
e.printStackTrace();
}
このコードは、サーバーの CLASSPATH にすべての関連クラスがあり、動的ロードが必要ない場合に機能します。
問題
サーバー側で CLASSPATH から削除WorkRequestSquareすると、クライアント側で例外がスローされます (サーバー側では何もスローされません)。
Error while submitting work request:
java.rmi.ServerException: RemoteException occurred in server thread; nested exception is:
java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is:
java.lang.ClassNotFoundException: WorkRequestSquare
at sun.rmi.server.UnicastServerRef.dispatch(Unknown Source)
...
WorkRequestSquareサーバーコードで明示的に言及されていないため、動的にロードできるはずですが、そうはなりません。
バイパス
Stuart Marks から、プロパティjava.rmi.server.useCodebaseOnlyを に設定する必要があることがわかりましたfalse。
このプロパティのデフォルト値は、JDK 7u21 でfalseからに変更されました。を使用してローカルに定義された場所を除いて、JVM が任意の場所からクラスを動的にロードするのを防ぐために設定します。これは、パラメーターをマーシャリングするときにクライアント JVM によって設定されたコードベース値が、サーバーによって無視されることを意味します。true useCodebaseOnlytruejava.rmi.server.codebaseWorkRequestSquareuseCodebaseOnlytrue
サーバーで がにuseCodebaseOnly設定さfalseれ、WorkRequestSquareクラスがサーバーの CLASSPATH から削除されると、サーバーは HTTP サーバーからクラス定義を取得するようになりました。これは有効なバイパスです。
質問
クライアントとサーバーのプロパティの値が同じであるため、まだ何か異常がありcodebaseます。
useCodebaseOnlyサーバーにデフォルト設定された場合true、JVM は RMI ストリームに追加されたクライアントを無視する必要がありましたが、クラスを取得するためにcodebase独自のものを使用する必要がありました。codebaseWorkRequestSquare
codebaseクライアントとサーバーの値が同じであるため、これはとにかく成功するはずです。
誰かがその問題に光を当てることができますか?