最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java中的上下文加載器ContextClassLoader詳解

 更新時間:2023年10月07日 09:46:43   作者:邋遢的流浪劍客  
這篇文章主要介紹了Java中的上下文加載器ContextClassLoader詳解,ContextClassLoader是通過Thread.currentThread().getContextClassLoader()返回該線程上下文的ClassLoader,需要的朋友可以參考下

ContextClassLoader

ContextClassLoader是通過 Thread.currentThread().getContextClassLoader() 返回該線程上下文的ClassLoader

1、前置知識

在講解ContextClassLoader之前,需要先提兩個知識點(diǎn):

1)雙親委派模型

在這里插入圖片描述

  • 啟動類加載器(Bootstrap ClassLoader):負(fù)責(zé)將放在<JAVA HOME>\lib目錄中的,或者被-Xbootclasspath參數(shù)所指定的路徑中的,并且是虛擬機(jī)識別的類庫加載到虛擬機(jī)內(nèi)存中。啟動類加載器無法被Java程序直接引用,用戶在編寫自定義類加載器時,如果需要把加載請求委派給引導(dǎo)類加載器,那直接使用null代替即可
  • 擴(kuò)展類加載器(ExtClassLoader):由sun.misc.Launcher$ExtClassLoader實(shí)現(xiàn),它負(fù)責(zé)加載<JAVA HOME>\lib\ext目錄中的,或者被java.ext.dirs系統(tǒng)變量所指定的路徑中的所有類庫,開發(fā)者可以直接使用擴(kuò)展類加載器
  • 應(yīng)用程序類加載器(AppClassLoader):由sun.misc.Launcher$AppClassLoader實(shí)現(xiàn)。由于這個類加載器是ClassLoader中的getSystemClassLoader()方法的返回值,所以一般也稱它為系統(tǒng)類加載。它負(fù)責(zé)加載用戶類路徑(ClassPath)上所有指定的類庫,開發(fā)者可以直接使用這個類加載器,如果應(yīng)用程序中沒有自定義過自己的類加載器,一般情況下這個就是程序中默認(rèn)的類加載器

類加載之間的這種層次關(guān)系,稱為類加載器的雙親委派模型。雙親委派模型要求除了頂層的啟動類加載器外,其余的類加載器都應(yīng)當(dāng)有自己的父類加載器。這里類加載器之間的父子關(guān)系一般不會以繼承的關(guān)系來實(shí)現(xiàn),而是都使用組合關(guān)系來復(fù)用父加載器的代碼

雙親委派模型的工作過程:如果一個類加載器收到了類加載的請求,它首先不會自己去嘗試加載這個類,而是把這個請求委派給父類加載器去完成,每一個層次的類加載器都是如此,因此所有的加載請求最終都應(yīng)該傳送到頂層的啟動類加載器,只有當(dāng)父加載器反饋?zhàn)约簾o法完成這個加載請求(它的搜索范圍中沒有找到所需的類)時,子加載器才會嘗試自己去加載

使用雙親委派模型來組織類加載器之間的關(guān)系,有一個顯而易見的好處就是Java類隨著它的類加載器一起具備了一種帶有優(yōu)先級的層次關(guān)系。例如類 java.lang.Object ,它存放在 rt.jar 之中,無論哪一個類加載器要加載這個類,最終都是委派給處于模型最頂端的啟動類加載器進(jìn)行加載,因此Object類在程序的各種類加載器環(huán)境中都是同一個類

2)如果一個類由類加載器A加載,那么這個類的依賴類也是由相同的類加載器加載

比如Spring作為一個Bean工廠,它需要創(chuàng)建業(yè)務(wù)類的實(shí)例,并且在創(chuàng)建業(yè)務(wù)類實(shí)例之前需要加載這些類。Spring是通過調(diào)用 Class.forName 來加載業(yè)務(wù)類的。調(diào)用 Class.forName() 的時候,會獲取調(diào)用該方法的類的類加載器,使用該類加載器來加載 Class.forName() 中傳入的類,代碼如下:

public final class Class<T> implements java.io.Serializable,
                              GenericDeclaration,
                              Type,
                              AnnotatedElement {
    @CallerSensitive
    public static Class<?> forName(String className)
                throws ClassNotFoundException {
      	// 獲取調(diào)用該方法的類
        Class<?> caller = Reflection.getCallerClass();
      	// ClassLoader.getClassLoader獲取調(diào)用該方法的類的類加載器
        return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
    }

2、為什么需要ContextClassLoader?

當(dāng)我們需要加載一個類,從自定義ClassLoader,到AppClassLoader,再到ExtClassLoader,最后到Bootstrap ClassLoader。沒問題, 很順利。這是從下到上加載。但是反過來,當(dāng)從上到下加載的時候,這個變得是一個不可能完成的任務(wù)。為了彌補(bǔ)這個缺陷, 特定設(shè)計的ContextClassLoader

這里你可能會有個疑問:為什么會出現(xiàn)從上到下加載的情況。比如一個類是由Bootstrap ClassLoader加載,該類引用了一個我們自己開發(fā)的類(該類能被AppClassLoader加載但不能被Bootstrap ClassLoader加載),由如果一個類由類加載器A加載,那么這個類的依賴類也是由相同的類加載器加載可知:默認(rèn)情況下我們自己開發(fā)的類會被Bootstrap ClassLoader嘗試加載,最終會由于無法加載到類而拋出異常

以SPI為例,SPI接口屬于Java核心庫,由BootstrapClassLoader加載,當(dāng)SPI接口想要引用第三方實(shí)現(xiàn)類的具體方法時,BootstrapClassLoader無法加載Classpath下的第三方實(shí)現(xiàn)類,這時就需要使用線程上下文類加載器ContextClassLoader來解決。借助這種機(jī)制可以打破雙親委托機(jī)制限制

SPI核心類ServiceLoader源碼如下:

public final class ServiceLoader<S>
    implements Iterable<S>
{
    public static <S> ServiceLoader<S> load(Class<S> service) {
      	// 線程上下文類加載器,在Launcher類的構(gòu)造器中被賦值為AppClassLoader,它可以讀到ClassPath下的自定義類
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        return ServiceLoader.load(service, cl);
    }     

在這里插入圖片描述

3、ContextClassLoader默認(rèn)為AppClassLoader

JVM啟動時,會去調(diào)用Launcher類的構(gòu)造方法:

public class Launcher {
    public Launcher() {
        ClassLoader extcl;
        try {
            // 首先創(chuàng)建擴(kuò)展類加載器
            extcl = ExtClassLoader.getExtClassLoader();
        } catch (IOException e) {
            throw new InternalError(
                    "Could not create extension class loader");
        }
        // Now create the class loader to use to launch the application
        try {
            // 再創(chuàng)建AppClassLoader并把extcl作為父加載器傳遞給AppClassLoader
            loader = AppClassLoader.getAppClassLoader(extcl);
        } catch (IOException e) {
            throw new InternalError(
                    "Could not create application class loader");
        }
        // 設(shè)置線程上下文類加載器,稍后分析
        Thread.currentThread().setContextClassLoader(loader);
        // 省略其他代碼...
    }

Launcher初始化時首先會創(chuàng)建ExtClassLoader類加載器,然后再創(chuàng)建AppClassLoader并把ExtClassLoader傳遞給它作為父類加載器,還把AppClassLoader默認(rèn)設(shè)置為線程上下文類加載器

4、子線程ContextClassLoader默認(rèn)為父線程的ContextClassLoader

Thread在 init() 方法中會把子線程ContextClassLoader設(shè)置為父線程的ContextClassLoader

public
class Thread implements Runnable {
    private ClassLoader contextClassLoader;
    private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc,
                      boolean inheritThreadLocals) {
        // 省略其他代碼...
      	// 當(dāng)前線程為父線程
        Thread parent = currentThread();
        SecurityManager security = System.getSecurityManager();
        if (g == null) {
            /* Determine if it's an applet or not */
            /* If there is a security manager, ask the security manager
               what to do. */
            if (security != null) {
                g = security.getThreadGroup();
            }
            /* If the security doesn't have a strong opinion of the matter
               use the parent thread group. */
            if (g == null) {
                g = parent.getThreadGroup();
            }
        }
        /* checkAccess regardless of whether or not threadgroup is
           explicitly passed in. */
        g.checkAccess();
        /*
         * Do we have the required permissions?
         */
        if (security != null) {
            if (isCCLOverridden(getClass())) {
                security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
            }
        }
        g.addUnstarted();
        this.group = g;
        this.daemon = parent.isDaemon();
        this.priority = parent.getPriority();
      	// 子線程ContextClassLoader設(shè)置為父線程的ContextClassLoader
        if (security == null || isCCLOverridden(parent.getClass()))
            this.contextClassLoader = parent.getContextClassLoader();
        else
            this.contextClassLoader = parent.contextClassLoader;
        // 省略其他代碼...
    }

到此這篇關(guān)于Java中的上下文加載器ContextClassLoader詳解的文章就介紹到這了,更多相關(guān)ContextClassLoader詳解內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • idea2023設(shè)置啟動參數(shù)、單元測試啟動參數(shù)

    idea2023設(shè)置啟動參數(shù)、單元測試啟動參數(shù)

    在使用IDEA進(jìn)行開發(fā)時,我們可以通過設(shè)置一些啟動參數(shù)來優(yōu)化開發(fā)環(huán)境的性能和體驗(yàn),具有一定的參考價值,感興趣的可以了解一下
    2023-11-11
  • Java內(nèi)存模型可見性問題相關(guān)解析

    Java內(nèi)存模型可見性問題相關(guān)解析

    這篇文章主要介紹了Java內(nèi)存模型可見性問題相關(guān)解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-12-12
  • java使用common-fileupload實(shí)現(xiàn)文件上傳

    java使用common-fileupload實(shí)現(xiàn)文件上傳

    這篇文章主要為大家詳細(xì)介紹了java使用common-fileupload實(shí)現(xiàn)文件上傳的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-10-10
  • java實(shí)現(xiàn)excel導(dǎo)入數(shù)據(jù)的工具類

    java實(shí)現(xiàn)excel導(dǎo)入數(shù)據(jù)的工具類

    這篇文章主要介紹了java實(shí)現(xiàn)的excel導(dǎo)入數(shù)據(jù)的工具類,需要的朋友可以參考下
    2014-03-03
  • JDBC中Statement和Preparement的使用講解

    JDBC中Statement和Preparement的使用講解

    今天小編就為大家分享一篇關(guān)于JDBC中Statement和Preparement的使用講解,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-01-01
  • Java線程的6種狀態(tài)及切換教程

    Java線程的6種狀態(tài)及切換教程

    這篇文章主要給大家介紹了關(guān)于Java線程的6種狀態(tài)及切換教程,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • MyEclipse2018中安裝Mybatis generator插件的實(shí)現(xiàn)步驟

    MyEclipse2018中安裝Mybatis generator插件的實(shí)現(xiàn)步驟

    這篇文章主要介紹了MyEclipse2018中安裝Mybatis generator插件的實(shí)現(xiàn)步驟,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-02-02
  • Java如何修改.class文件變量

    Java如何修改.class文件變量

    這篇文章主要介紹了Java如何修改.class文件變量,幫助大家更好的理解和學(xué)習(xí)Java,感興趣的朋友可以了解下
    2020-09-09
  • SpringBoot@Profile注解和Spring?EL(多環(huán)境注入)

    SpringBoot@Profile注解和Spring?EL(多環(huán)境注入)

    為了方便, Spring還提供了 Profile機(jī)制, 使我們可以很方便地實(shí)現(xiàn)各個環(huán)境之間的切換,在使用DI來依賴注入的時候,能夠根據(jù)@profile標(biāo)明的環(huán)境,將注入符合當(dāng)前運(yùn)行環(huán)境的相應(yīng)的bean,本文通過示例代碼介紹SpringBoot@Profile注解和Spring?EL,需要的朋友可以參考下
    2024-02-02
  • Spring 切面執(zhí)行鏈的實(shí)現(xiàn)示例

    Spring 切面執(zhí)行鏈的實(shí)現(xiàn)示例

    在實(shí)際應(yīng)用中,一個方法通常會被多個切面攔截,本文主要介紹了Spring 切面執(zhí)行鏈的實(shí)現(xiàn)示例,具有一定的參考價值,感興趣的可以了解一下
    2025-10-10

最新評論

安泽县| 三原县| 寻甸| 闽侯县| 铁岭县| 水城县| 新源县| 美姑县| 凉山| 成武县| 阿拉善右旗| 徐州市| 大同市| 长沙县| 那坡县| 尚义县| 建平县| 绥滨县| 叙永县| 淮南市| 台东县| 黑山县| 龙里县| 金坛市| 游戏| 科技| 固原市| 祁门县| 扶绥县| 顺昌县| 文安县| 闵行区| 丽江市| 甘孜| 商城县| 承德县| 西峡县| 津南区| 丹寨县| 武冈市| 漳平市|