1

以下のテストケース。出力:

custom loading of: pkg.TestRun
ran.
wish this would run in my custom classloader

私がしたいのは、出力の 2 行目と 3 行目の間に「pkg.TestRun のカスタム読み込み」が表示されることです。

最初のクラスが親からロードされた場合でも、カスタム クラスローダーからクラスの依存関係をロードするにはどうすればよいですか? 私の実際のケースでは、 OtherClass に相当するものが親クラスローダーに認識されていないため、クラスが見つからないという例外が発生することに注意してください。

解決策の 1 つは、カスタム クラス ローダーで TestRun を明示的にロードすることです。ただし、TestRun をロードする方法は親クラスローダーに既に知られているため、個別に検索を管理する必要はありません。それは既に行われているためです。私が何もせずに既に管理されている場合、どうにかしてそれを理解するのは難しいかもしれません。なんでも。そして、私はsuper.getResource(nullを返す)やfindClass(すでに親をクラスローダーとして設定しています)のようなことをしようとしましたが、どちらもうまくいきませんでした。

では、親にクラスを見つけさせて、カスタム ローダーに定義させることはできますか? または、常にカスタムローダーを使用して依存関係を探すようにする方法はありますか?

package pkg;

public class TestCL {

    static class MyCL extends ClassLoader {
        MyCL(ClassLoader parent) {
            super(parent);
        }

        @Override
        public Class loadClass(String name, boolean resolve) throws ClassNotFoundException {
            System.out.println("custom loading of: " + name);
            return getParent().loadClass(name);
        }
    }

    public static void main(String[] args) throws Exception {
        MyCL cl = new MyCL(Thread.currentThread().getContextClassLoader());
        Thread.currentThread().setContextClassLoader(cl);
        cl.loadClass("pkg.TestRun").getMethod("run", new Class[] {}).invoke(null);
    }
}

class TestRun {
    public static void run() {
        System.out.println("ran.");
        OtherClass.runAlso();
    }
}

class OtherClass {
    public static void runAlso() {
        System.out.println("wish this would run in my custom classloader");
    }
}
4

2 に答える 2

0

解決策の 1 つは、親のクラスローダー (またはその場所が既にわかっているクラスローダー) を使用してクラスのバイトを読み取り、それをカスタム クラス ローダーで定義することです。

したがって、次のようなものです。

public static byte[] loadBytesForClass(ClassLoader loader, String fqn) throws IOException {
    InputStream input = loader.getResourceAsStream(fqn.replace(".", "/") + ".class");
    if (input == null) {
        System.out.println("Could not load bytes for class: " + fqn);
    }
    ByteArrayOutputStream output = new ByteArrayOutputStream();
    StringUtil.copy(input, output);
    return output.toByteArray();
}

次にdefineClass(name, bytes, 0, bytes.length)、これらのバイトを呼び出して、カスタム クラス ローダーで定義できます。

于 2012-12-21T18:35:29.227 に答える
0

問題は、カスタムクラスローダーを使用して何もロードしていなかったことです。
親にクラスをロードするように要求するため、すべてがメインクラスローダーによってロードされていました。

この変更されたコードを試してください:

package stackoverflow.june2012.classloader;

import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;

public class TestCL {

static class MyCL extends URLClassLoader {
    MyCL(URL[] urls) {
        // NOTE: No parent classloader!
        super(urls, null);
    }

    @Override
    public Class loadClass(String name, boolean resolve) throws ClassNotFoundException {
        System.out.println("custom loading of: " + name);
        return super.loadClass(name, resolve);
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        System.out.println("findClass: " + name);
        System.out.println("NOTE: Only called if this classloader does NOT have a parent");
        return super.findClass(name);
    }
}

public static void main(String[] args) throws Exception {
    URL url = new File("./bin").toURI().toURL();
    System.out.println("url to search for classes: " + url);
    MyCL cl = new MyCL(new URL[] {url});
    Thread.currentThread().setContextClassLoader(cl);
    Class loadClass = cl.loadClass("stackoverflow.june2012.classloader.TestRun");
    System.out.println("Loaded TestRun using classloader: " + loadClass.getClassLoader());
    loadClass.getMethod("run", new Class[] {}).invoke(null);
}

}

そして、他の2つのクラスを別のファイルに移動する必要がありました。そうしないと、別のクラスローダーでパッケージプライベートだったため、アクセスできません。

package stackoverflow.june2012.classloader;

public class TestRun {
    public static void run() {
    System.out.println("ran.");
    OtherClass.runAlso();
    }
}

class OtherClass {
    public static void runAlso() {
        System.out.println("wish this would run in my custom classloader");
    }
}
于 2012-06-30T10:16:45.620 に答える