簡體   English   中英

我怎樣才能使URLClassLoader表現得像這樣?

[英]How can I make a URLClassLoader behave like this?

我正在嘗試制作一個行為如下的URLClassLoader:

  • 如果要求提供名稱在給定包含集合中的課程,請照常加載
  • 否則,返回一個虛擬類

我無法使它正常工作。 在下面的嘗試中,我希望SpecialClassLoader成功加載Test$Thing 這樣做時,我希望它嘗試加載Test$SuperThing ,並且可以對虛擬類Nothing進行加載這一事實感到滿意。

但是,出現了問題,並拋出了NoClassDefFoundError以查找Test$SuperThing

有誰知道如何解決這一問題?

public class Test {

    private static class SuperThing {}

    private static class Thing extends SuperThing {}

    public static void main(String[] args) {
        Set<String> inclusions = new HashSet<String>();
        inclusions.add("Test$Thing"); // note Test$SuperThing is excluded
        URLClassLoader cl = (URLClassLoader) 
            Thread.currentThread().getContextClassLoader();
        SpecialClassLoader cll = 
            new SpecialClassLoader(cl.getURLs(), inclusions);
        try {
            cll.loadClass("Test$Thing"); // line 22 (see stacktrace below)
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    private static class Nothing {}

    private static final class SpecialClassLoader extends URLClassLoader {

        private final Set<String> inclusions;

            public SpecialClassLoader(URL[] urls, Set<String> inclusions) {
                super(urls);
                this.inclusions = inclusions;
            }

        @Override
        public Class<?> loadClass(String name) throws ClassNotFoundException {
            if (inclusions.contains(name)) {
                return findClass(name); // line 40 (see stacktrace below)
            }
            return Nothing.class;
        }
    }
}

編輯:這是我得到的stacktrace(上面的清單中指出了行號22和40):

Exception in thread "main" java.lang.NoClassDefFoundError: Test$SuperThing
        at java.lang.ClassLoader.defineClass1(Native Method)
        at java.lang.ClassLoader.defineClass(ClassLoader.java:620)
        at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:124)
        at java.net.URLClassLoader.defineClass(URLClassLoader.java:260)
        at java.net.URLClassLoader.access$000(URLClassLoader.java:56)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:195)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
        at Test$SpecialClassLoader.loadClass(Test.java:40)
        at Test.main(Test.java:22)

這是正在發生的事情。

  • 當您嘗試加載Test $ Thing時,defineClass方法會指出它需要加載Test $ Thing的超類。 即Test $ SuperThing。

  • 系統類加載器調用您的類加載器,該類加載器返回Nothing類。

  • 系統類加載器說“哇!該類沒有正確的完全合格的類名!”,並拋出NoClassDefFoundError

基本上,該系統類加載器可防止破壞JVM穩定性的事物。 如果允許自定義類加載器加載錯誤的類,則可能會發生令人討厭的事情。 例如,考慮在欺騙類加載器加載Nothing類之后,如果某些代碼調用為Test $ SuperThing類定義的某些方法,會發生什么情況。

如果您想做一些骯臟的技巧來代替某個類的虛擬版本,則需要使用正確的完全限定的類名,正確的超類和接口以及具有正確簽名的方法來動態生成字節碼。 簡而言之,您必須滿足二進制兼容性規則。 如果不這樣做,則無論您嘗試在自定義類加載器中執行什么操作,系統類加載器都將拒絕加載您的類。

坦白說,無論您想做什么,都應該采取完全不同的方法。

可以在編譯器的輸出中找到名為Test $ Thing.class的類嗎? 正如此處給出的代碼一樣,它永遠也不會被直接引用,也許編譯器會優化該類。 在這種情況下,反射無法找到該類。

如果是這種情況,您可以簡單地向該類添加一個(非反射)引用,以便對其進行編譯。

編輯:自己嘗試一下之后,我認為我找到了問題的根源。 如果我從Thing聲明中刪除了“ extendeds SuperThing”,它會抱怨找不到java.lang.Object。 可能是,類加載器還嘗試加載所有相關類(包括其擴展的類),但由於未在白名單中而無法加載。 但這是一個理論。

暫無
暫無

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

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