6

割り当て用の静的分析ツールを作成しています。これは、ASMライブラリを使用してJavaバイトコードを分析します。私たちが使用するASMの部分の1つは、クラスがClassLoaderからロードされることを要求します(または少なくとも要求するように見えます)。

ツールがクラスパスに.classファイルを必要とせずに.classファイルを分析できることを望んでいました。実行時に指定されたディレクトリから.classesをすでにロードし、InputStreamを使用してそれらを読み込みます。ほとんどの場合、これはASMで許容されます。SimpleVerifierただし、クラスをロードしようとするクラスなどがあります。

このシナリオでは、を呼び出すとロードされるように、ロードする.classファイルを登録することは可能Class.forName()ですか?または、これを可能にするためにClassLoaderを拡張する簡単な方法はありますか?


編集:に関する情報URLClassLoaderは役に立ちました。残念ながら、Thread.currentThread().setContextClassLoader()そのインスタンスを使用することは、このシナリオでは機能しませんでした。私が呼び出しているライブラリコードは、を使用したインスタンスの初期化時に取得するローダーを使用しますgetClass().getClassLoader()

URLClassLoaderを設定した時点では、クラスは初期化されていないため、contextClassLoaderはそのクラスをロードしないと思います。

応答を正しく理解しましたか?URLClassLoaderを使用してサードパーティのクラスをロードすることは可能でしょうか?

4

6 に答える 6

5

ほとんど。

クラスをどこかにコンパイルしている場合は、URLClassLoaderを使用してそれらをロードできます。次に、このClassLoaderを現在のスレッドのClassLoaderに設定できます。Thread.setContextClassLoader(ClassLoader)

ユーザーは、現在のスレッドコンテキストクラスローダーを取得し、それを使用してクラス定義にアクセスできます。

于 2009-12-09T14:03:52.980 に答える
5

まず、ASMは、ClassLoaderを使用してクラスに関する情報を取得しないように使用できます。

ASMフレームワークには、デフォルトでクラスをロードする場所がいくつかありますが、それらの場所はすべて、独自のサブクラスでオーバーライドできます。私の頭のてっぺんから:

  • ClassWriter.getCommonSuperClass()メソッドは、ClassWriter.COMPUTE_FRAMESフラグが使用されている場合にのみ呼び出され、ClassLoaderを使用してクラスに関する情報を取得しないように上書きできます。その例は、 ClassInfo抽象化を導入するClassWriterComputeFramesTestにあります。
  • 同様に、SimpleVerifier.getClass()メソッドはSimpleVerifier.isAssignableFrom()によって使用され後者を上書きし、ClassInfo抽象化を使用して共通のスーパータイプを見つけることができます。私が間違っていなければ、AspectWerkzプロジェクトはその型パターンマッチングコードに同様のことを実装していました。SimpleVerifier.setClassLoader()メソッドがあることにも注意してください 。これは、独自のクラスをロードする場合に使用できます。

ちなみに、SunのJVMでは、ロードされたクラスはPermGen領域に到達し、アンロードできないため、静的コード分析の目的でのみクラスをロードすることはお勧めできません。 IDEなどの長期的なプロセスに統合されています。

于 2009-12-16T19:04:09.113 に答える
2

はい、 URLClassLoaderを使用できます

実行時にクラスをロードするテストがあります。このクラスはクラスパスに含まれていません(テストが実行されたときにも存在しません)。後でロードされ、正常に機能します。

これがコードです。

void testHello() throws MalformedURLException, ClassNotFoundException {
    URL[] url = {
            new URL("file:/home/oreyes/testwork/")
    };

    try {
        new URLClassLoader(url).loadClass("Hello");
        throw new AssertionError("Should've thrown ClassNotFoundException");
    } catch ( ClassNotFoundException cnfe ){}


    c.process();// create the .class file 

    new URLClassLoader(url).loadClass("Hello");

    // it works!!
}

この質問から引用。

于 2009-12-09T14:16:58.513 に答える
2

私の知る限り、実行時にSystemクラスローダーを拡張することはできませんが、URLClassLoaderを使用して、任意の場所(jarまたはディレクトリ)からクラスを動的にロードできます。

于 2009-12-09T14:01:22.987 に答える
2

アプリケーションの起動時に「ランチャー」をセットアップしURLClassLoaderて、クラスパス上の.class場所と独自の場所を渡し、そのクラスローダーからアプリケーションを開始することができます。

によってSimpleVerifierロードされるURLClassLoaderと、追加の場所からクラスをロードすることもできます。

于 2009-12-09T14:12:42.390 に答える
1

非常にシンプルな独自のClassLoaderを作成しました。

 /**
 * Used to hold the bytecode for the class to be loaded.
 */
private final static ThreadLocal<byte[]> BYTE_CODE = new ThreadLocal<byte[]>();

@Override
protected Class<?> findClass(final String name) throws ClassNotFoundException {
    final byte[] bytes = BYTE_CODE.get();
    if (null == bytes) {
        throw new ClassNotFoundException(name);
    }
    return this.defineClass(null, bytes, 0, bytes.length);
}
于 2010-02-10T08:51:11.723 に答える