亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

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

ContextClassLoader

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

1、前置知識

在講解ContextClassLoader之前,需要先提兩個知識點:

1)雙親委派模型

在這里插入圖片描述

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

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

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

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

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

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

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

2、為什么需要ContextClassLoader?

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

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

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

SPI核心類ServiceLoader源碼如下:

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

在這里插入圖片描述

3、ContextClassLoader默認為AppClassLoader

JVM啟動時,會去調用Launcher類的構造方法:

public class Launcher {
    public Launcher() {
        ClassLoader extcl;
        try {
            // 首先創(chuàng)建擴展類加載器
            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");
        }
        // 設置線程上下文類加載器,稍后分析
        Thread.currentThread().setContextClassLoader(loader);
        // 省略其他代碼...
    }

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

4、子線程ContextClassLoader默認為父線程的ContextClassLoader

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

public
class Thread implements Runnable {
    private ClassLoader contextClassLoader;
    private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc,
                      boolean inheritThreadLocals) {
        // 省略其他代碼...
      	// 當前線程為父線程
        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設置為父線程的ContextClassLoader
        if (security == null || isCCLOverridden(parent.getClass()))
            this.contextClassLoader = parent.getContextClassLoader();
        else
            this.contextClassLoader = parent.contextClassLoader;
        // 省略其他代碼...
    }

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

相關文章

  • @FeignClient?path屬性路徑前綴帶路徑變量時報錯的解決

    @FeignClient?path屬性路徑前綴帶路徑變量時報錯的解決

    這篇文章主要介紹了@FeignClient?path屬性路徑前綴帶路徑變量時報錯的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • springboot整合netty框架實現(xiàn)站內(nèi)信

    springboot整合netty框架實現(xiàn)站內(nèi)信

    Netty 是一個基于NIO的客戶、服務器端編程框架,使用Netty 可以確保你快速和簡單的開發(fā)出一個網(wǎng)絡應用,這篇文章主要介紹了springboot整合netty框架的方式小結,需要的朋友可以參考下
    2022-12-12
  • SpringBoot啟動嵌入式Tomcat的實現(xiàn)步驟

    SpringBoot啟動嵌入式Tomcat的實現(xiàn)步驟

    本文主要介紹了淺談SpringBoot如何啟動嵌入式Tomcat,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • Springboot 全局時間格式化三種方式示例詳解

    Springboot 全局時間格式化三種方式示例詳解

    時間格式化在項目中使用頻率是非常高的,當我們的 API? 接口返回結果,需要對其中某一個 date? 字段屬性進行特殊的格式化處理,通常會用到 SimpleDateFormat? 工具處理,這篇文章主要介紹了3 種 Springboot 全局時間格式化方式,需要的朋友可以參考下
    2024-01-01
  • 使用Redis incr解決并發(fā)問題的操作

    使用Redis incr解決并發(fā)問題的操作

    這篇文章主要介紹了使用Redis incr解決并發(fā)問題的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-11-11
  • 深扒Java中POJO、VO、DO、DTO、PO、BO、AO、DAO的概念和區(qū)別以及如何應用

    深扒Java中POJO、VO、DO、DTO、PO、BO、AO、DAO的概念和區(qū)別以及如何應用

    po vo bo dto dao 和 pojo 是軟件開發(fā)中經(jīng)常使用的一些概念,用于設計和實現(xiàn)對象模型,下面將分別解釋這些概念的含義及其在開發(fā)中的應用,這篇文章主要給大家介紹了關于Java中POJO、VO、DO、DTO、PO、BO、AO、DAO的概念和區(qū)別以及如何應用的相關資料,需要的朋友可以參考下
    2024-08-08
  • 如何使用MAVEN打JAR包(直接使用)

    如何使用MAVEN打JAR包(直接使用)

    這篇文章主要介紹了如何使用MAVEN打JAR包(直接使用),文中通過實例代碼介紹了maven?使用assembly插件進行打包的方法,需要的朋友可以參考下
    2023-03-03
  • SpringBoot整合MongoDB的步驟詳解

    SpringBoot整合MongoDB的步驟詳解

    這篇文章主要介紹了SpringBoot整合MongoDB的步驟詳解,幫助大家更好的理解和學習使用SpringBoot框架,感興趣的朋友可以了解下
    2021-04-04
  • Maven打包JavaWeb項目的兩種實現(xiàn)方式

    Maven打包JavaWeb項目的兩種實現(xiàn)方式

    介紹了兩種Maven打包Web項目的方式:通過Eclipse和通過命令行,Eclipse方式包括清理、打包、跳過測試、輸入?Goals?等步驟,命令行方式包括進入項目目錄、執(zhí)行?clean?和?package?命令、跳過測試等步驟,注意事項包括確保有JDK環(huán)境、正確配置pom.xml文件和修改版本號
    2025-02-02
  • SpringBoot的啟動速度優(yōu)化

    SpringBoot的啟動速度優(yōu)化

    隨著我們項目的不斷迭代 Bean 的數(shù)量會大大增加,如果都在啟動時進行初始化會非常耗時,本文主要介紹了SpringBoot的啟動速度優(yōu)化,感興趣的可以了解一下
    2023-09-09

最新評論