web-dev-qa-db-ja.com

カスタムClassLoaderを使用する方法

みなさん、こんにちは。ご清聴ありがとうございました!私は簡単で明白な問題を抱えていますが、それでも行き詰まっています。

動的に作成されたJava=カスタムクラスローダーを介してサードパーティのライブラリで使用されるクラスを提供したい。

今私の問題は、自分で直接ロードしないときに、このクラスをロードするために使用するカスタムClassLoaderを設定するにはどうすればよいですか?

ClassLoaderを使用して特定のクラスをロードすると、それがこのクラスのClassLoaderになり、そのクラスからロードされたすべてのクラスが私のClassLoaderを介してチャネリングされると思いました。

この公式チュートリアルに従って、カスタムClassLoaderを作成しました: http://Java.Sun.com/developer/onlineTraining/Security/Fundamentals/magercises/ClassLoader/help.html

_public class DynamicClassloader extends ClassLoader {

    private Map<String, Class<?>> classesMap = new HashMap<String, Class<?>>();

    public DynamicClassloader(ClassLoader parent) {
        // Also tried super(parent);
        super(Sun.misc.Launcher.getLauncher().getClassLoader());
    }

    // Adding dynamically created classes
    public void defineClass(String name, Class<?> clazz) {
        classesMap.put(name, clazz);
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        // load from parent
        Class<?> result = findLoadedClass(name);
        if (result != null) {
            return result;
        }
        try {
            result = findSystemClass(name);
        } catch (Exception e) {
            // Ignore these
        }
        if (result != null) {
            return result;
        }
        result = classesMap.get(name);
        if (result == null) {
            throw new ClassNotFoundException(name);
        }
        return result;
    }
}
_

私はそれをそのようなコードのどこかで使用したかった:

_ClassLoader thisClassLoader = this.getClass().getClassLoader();
((DynamicClassloader) thisClassLoader).defineClass(className, dynClass);
_

私の問題は、サードパーティライブラリクラスのfindSystemClass(name)を呼び出すと、親ClassLoaderがこのクラスを見つけ(クラスパス上にあるため)、そのClassLoaderになることです。また、親ClassLoaderはカスタムClassLoaderを認識していないため、事実上使用されなくなり、this.getClass().getClassLoader()をDynamicClassLoaderにキャストできません。

別のアプローチは、JVM引数_-Djava.system.class.loader=my.DynamicClassloader_を介して、ClassLoaderをシステムClassLoaderに設定することです。しかし、それは私にStackOverflowErrorを与えます:

_    ...
at de.unisaarland.cs.st.DynamicClassloader.findClass(DynamicClassloader.Java:39)
at Java.lang.ClassLoader.loadClass(ClassLoader.Java:307)
at Java.lang.ClassLoader.loadClass(ClassLoader.Java:248)
at Java.lang.ClassLoader.findSystemClass(ClassLoader.Java:916)
at de.unisaarland.cs.st.DynamicClassloader.findClass(DynamicClassloader.Java:39)
    ...
_

これは本当に簡単にできるはずですが、私は今アイデアから外れています...どんな助けでも大歓迎です!

30
roesslerj

私が質問を理解しているかわからない、あなたはサードパーティのlibを持っていて、クラスローダーを使ってクラスをロードしたいと思っています。

運が良ければ、サードパーティのlibはThread.currentThread().setContextClassLoader(myClassLoader)を使用して設定できるスレッドコンテキストクラスローダーを使用します。同じスレッドで、このクラスローダーにThread.currentThread().getContextClassLoader()...でアクセスできます。

別のポイントですが、コンテキストで重要であるかどうかはわかりませんが、親に委譲する前にクラスをロードしようとする、親から最後のクラスローダーを作成することもできます(最初に委任するのではなく)

コメントの後に編集:

ライブラリがスレッドコンテキストクラスローダーに依存していない場合、parent_lastクラスローダーは違いをもたらします。そのため、ライブラリをparent-lastクラスローダーでロードする必要があるため、クラスローダーをその親ローダー(親)ではなく、ライブラリのクラスローダーとして設定します。クラスローダーの)...

親優先の動作でクラスローダーを作成することもできますが、サードパーティのライブラリ用です...

そしてクラスローダーについての良いリンク...

22
pgras