簡體   English   中英

如何使Java使用我的類加載器進行類解析

[英]How to make Java use my classloader for class resolution

下面的測試用例。 輸出:

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

我想要發生的是看到“自定義加載:pkg.TestRun”顯示在輸出的第二行和第三行之間。

即使從父級加載了第一個類,如何從自定義的類加載器中加載類的依賴關系呢? 請注意,在我的真實情況下,我得到一個未找到的類異常,因為父類加載器不知道OtherClass的等效項。

我知道一種解決方案是讓自定義類加載器顯式加載TestRun。 但是,父類加載器已經知道如何加載TestRun,並且我不想單獨管理它,因為它已經完成了,因此我可能很難以某種方式弄清楚何時不用我就可以對其進行管理任何東西。 而且我嘗試做類似super.getResource(返回null)或findClass(已經將parent設置為classloader)的東西,但是都沒有用。

因此,我可以讓父級找到該類,但自定義加載程序對其進行定義嗎? 或者,是否只有一種方法可以使它始終使用我的自定義加載程序來查找依賴項?

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");
    }
}

問題是您沒有使用自定義類加載器加載任何內容
它要求其父級加載該類,因此所有內容均由主類加載器加載。

嘗試以下修改的代碼:

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);
}

}

而且我必須將其他兩個類移到一個單獨的文件中,否則無法訪問它,因為它在另一個類加載器中是程序包私有的:

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");
    }
}

一種解決方案是使用父類加載器(或已經知道其位置的父類加載器)讀取類的字節,然后在自定義類加載器中對其進行定義。

因此,如下所示:

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)以在自定義類加載器中對其進行定義。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM