2

Class.forName を使用して、実行時にファイルシステム上の .jar ファイルからクラスを動的にロードしようとしています。ロードしようとしているクラスは、別の .jar ファイルにインターフェイスを実装しているため、独自の URLClassLoader を使用して 2 つの .jar ファイルを参照しています。

このコードは、Web アプリのコンテキスト以外で呼び出された場合に機能します (メソッドをコピーして別のプログラムに貼り付け、メインから呼び出すことでこれをテストしました)。ただし、Web アプリケーションを実行/デバッグすると (NetBeans を使用しています)、コードが失敗します。jar_file_dependencies.jar で指定されたインターフェースにインスタンスをキャストしようとすると、newInstance メソッドが ClassCastException をスローします。

これが役立つ場合の関連コードは次のとおりです。

       File gameJar = new File("C:\\file_path\\jar_file.jar");

       File gameDependenciesJar = new File("C:\\file_path\\jar_file_dependencies.jar");

        URLClassLoader cl = new URLClassLoader(new URL[]
                {
                    gameJar.toURI().toURL(),
                    gameDependenciesJar.toURI().toURL()
                });

        Class clazz = Class.forName("MyClass", true, cl);

        IMyClass myClass = (IMyClass)clazz.newInstance();

        System.out.println(game);

    } catch (Exception e)
    {
        System.out.println(e.getMessage());
    }

このコードがあるプログラムで機能し、別のプログラムでは機能しない理由についての提案は大歓迎です。

どうもありがとう、ダン

4

2 に答える 2

2

毛むくじゃらの詳細をあまり説明しない簡単な答え: gameJar と gameDependenciesJar の一方または両方には、おそらく IMyClass クラス/インターフェイスの定義が含まれています。子クラスローダを使用するときの経験則は、子クラスローダに「共有」クラスを含めないことです。これらは親クラスローダにのみ存在する必要があります。

部分的な説明: 通常、Web アプリのクラスローダーには、通常のクラスローダーとは異なる委任ポリシーがあります。多くの場合、彼らは親のクラスよりも子供のクラスを好みます。通常のクラスローダは通常、子のクラスよりも親のクラスを優先します。Web アプリでは、IMyClass クラスの 2 つの個別の定義が作成されます (親クラスローダーに定義が 1 つ、子に定義が 1 つ)。通常のアプリでは、子クラスローダーの IMyClass 定義が無視されるため、(親クラスローダーで) 1 つの定義のみが読み込まれ、すべてが満足します。

于 2010-12-09T20:30:23.650 に答える
0

たぶんこれが役立つでしょう(未テスト)

ClassLoader clsLoader = Thread.currentThread().getContextClassLoader();
if (clsLoader == null) {
    clsLoader = this.getClass().getClassLoader();
}

URLClassLoader cl = new URLClassLoader(new URL[]
                {
                    gameJar.toURI().toURL(),
                    gameDependenciesJar.toURI().toURL()
                }, clsLoader);

また、単にクラスを呼び出すのではなく、クラスの完全な宣言名を渡す必要があります。MyClassMyClassClass.forName()

例えば

Class clazz = Class.forName("com.xxxx.yyy.MyClass", true, cl);
于 2010-12-09T20:42:43.093 に答える