簡體   English   中英

我怎么知道當前的java中的classLoader

[英]how can I know the current classLoader in java

我正在學習加載Java類的過程,遇到一些困惑。

我知道在加載Java類時當前的classLoader不會直接加載Java類 ,它將委托給其父classLoader (一個遞歸過程),直到其父不能加載該類為止。


問題是當前的classLoader是什么? 引導程序? 延期? 應用程式?
如何獲取當前的classLoader? 而且我知道有一個API:

xxx.Class.getClassLoader();

但我不確定返回值是否為currentClassLoader 我認為應該是實際加載此java類的classLoader。

為了更詳細地描述我的問題,我將舉一個例子。
我在博客中獲得了以下內容。

ThreadContextClassLoader用於處理Java SPI ,接口在java core lib定義,由Bootstrap ClassLoader加載 ,第三方實現這些接口,然后由AppClassLoader加載jar
解決方案:傳統的classLoader無法處理這種情況,因為當我們在核心庫中使用第三方工具時,它無法發現第三方jar。

我能理解的大多數上述內容,但解決方案使我感到困惑:例如,接口CoreA和類CoreB在Java core lib ,應由Bootstrap ClassLoader加載 ,而AImpl是第三方的A的實現,應為由AppClass加載程序加載

代碼段如下:

 public Interface CoreA{
     void add();
 }

 public Interface AImpl implements CoreA{
     void add(){};
 }

 public class B{
      public void demo(){
         a = new AImpl();
      }
 }

然后,如果我們引用Bmain method ,那么我們將加載B因為類裝載程序 B自舉然后大約AImpl當前Loader是自舉所以它不能找到? 我不知道這是否是我的猜測?

任何建議將被認真考慮。

一般來說,您是正確的,找不到它。 讓我向您展示以下示例。 假設我們有3個類: ABMain像這樣:

public class A {
    public String a() {
        return "a";
    }
}

public class B {
    public String b() {
        return new A().a();
    }
}

public class Main {
    public static void main(String... args) {
        System.out.println(new B().b());
    }
}

然后將這些類打包到相應的jar中: a.jarb.jar並將Main.class放入工作目錄中。 之后,讓我們測試以下方案:

1)一切( A.classB.classMain.class )都由system classloader並正常工作:

$ java -cp .:a.jar:b.jar Main
a

2) B.classsystem classloaderA.classbootstrap classloader並且一切仍然正常,因為system classloadersystem classloader委托給bootstrap classloader (只是因為bootstrap classloader可以加載):

$ java -Xbootclasspath/a:a.jar -cp .:b.jar Main
a

3) A.classsystem classloaderB.classbootstrap classloader (您的情況)。 在這種情況下,在加載B.class過程中,當前的classloader是bootstrap classloader ,但是找不到B.class並失敗:

$ java -Xbootclasspath/a:b.jar -cp .:a.jar Main
Exception in thread "main" java.lang.NoClassDefFoundError: A
        at B.b(B.java:4)
        at Main.main(Main.java:4)

讓我們更仔細地看看最后一個例子。 這里發生了什么事:

  1. 嘗試使用public static main(String[] args)方法查找類

    1.1。 system classloader尚未加載,因此委托給extension classloader

    1.2。 extension classloader尚未加載,因此委托給bootstrap classloader

    1.3。 bootstrap classloader尚未加載並嘗試加載,無法加載並將控制權返回給extension classloader

    1.4。 extension classloader嘗試加載,無法加載並將控制權返回給system classloader

    1.5。 system classloader加載system classloader加載Main.class

  2. Main.class已處理,我們嘗試使用當前的classloader system classloader加載B.class

    2.1。 system classloader尚未加載,因此委托給extension classloader

    2.2。 extension classloader尚未加載,因此委托給bootstrap classloader

    2.3。 bootstrap classloader尚未加載並加載B.class

  3. B.class已處理,我們嘗試使用當前的類加載器bootstrap classloader加載A.class

    3.1。 bootstrap classloader尚未加載,並嘗試加載並失敗

希望對您有幫助。

“當前類加載器”是引用它的類的真實類加載器實際加載該類)。

例如,如果class AclassLoaderext classloader,class A引用類BCD 那么BCD的“當前類加載器”是ext classLoader 當然, 主類的“當前classLoader”是System classLoader

當類A嘗試加載另一個類B時,加載A的ClassLoader是當前的ClassLoader。 當前一詞含糊地指的是執行上下文-例如,如何最終觸發當前類加載調用的方法。

沒有方法(例如getCurrentClassLoader )簡單地給出當前的ClassLoader,但是有一些api方法在內部使用當前的ClassLoader的概念。 例如, Class.forName(String className)

如果檢查該方法的實現方式,它將告訴您“當前類加載器”的含義:

public static Class<?> forName(String className) throws ClassNotFoundException {
    Class<?> caller = Reflection.getCallerClass();
    return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}

如果可以掌握Class實例,則始終可以通過調用Class::getClassLoader()方法來請求其背后的加載器。 那將是您當前的類加載器。 但是,棘手的一點是,確定加載程序是引導程序,擴展程序還是系統類加載程序。 棘手的原因是它是特定於實現的,並且您始終可以實現自己的類加載機制。

@dmitrievanthony給出的示例說明了事情如何變得真正復雜。 這是JNDI面臨的類似情況,也是引入Thread.getContextClassLoader()的原因。 在這里了解更多

引用文章中最相關的文章:

...根據定義,當前的類加載器將加載並定義當前方法所屬的類。 當類之間的動態鏈接在運行時解析時,以及使用Class.forName(),Class.getResource()和類似方法的單參數版本時,將暗含該類加載器。 X.class類文字等語法構造也使用它...

暫無
暫無

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

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