1、雙親委派模型
- 原理:當一個類加載器收到類加載任務時,會先交給自己的父加載器去完成,因此最終加載任務都會傳遞到最頂層的BootstrapClassLoader,只有當父加載器無法完成加載任務時,才會嘗試自己來加載。
具體:根據雙親委派模式,在加載類文件的時候,子類加載器首先將加載請求委托給它的父加載器,父加載器會檢測自己是否已經加載過類,如果已經加載則加載過程結束,如果沒有加載的話則請求繼續向上傳遞直Bootstrap ClassLoader。如果請求向上委托過程中,如果始終沒有檢測到該類已經加載,則Bootstrap ClassLoader開始嘗試從其對應路勁中加載該類文件,如果失敗則由子類加載器繼續嘗試加載,直至發起加載請求的子加載器為止。
- 采用雙親委派模式可以保證類型加載的安全性,不管是哪個加載器加載這個類,最終都是委托給頂層的BootstrapClassLoader來加載的,只有父類無法加載自己猜嘗試加載,這樣就可以保證任何的類加載器最終得到的都是同樣一個Object對象。
2.雙親委派模型缺陷
- 在雙親委派模型中,子類加載器可以使用父類加載器已經加載的類,而父類加載器無法使用子類加載器已經加載的。這就導致了雙親委派模型並不能解決所有的類加載器問題。
- 案例:Java 提供了很多服務提供者接口(Service Provider Interface,SPI),允許第三方為這些接口提供實現。常見的 SPI 有 JDBC、JNDI、JAXP 等,這些SPI的接口由核心類庫提供,卻由第三方實現,這樣就存在一個問題:SPI 的接口是 Java 核心庫的一部分,是由BootstrapClassLoader加載的;SPI實現的Java類一般是由AppClassLoader來加載的。BootstrapClassLoader是無法找到 SPI 的實現類的,因為它只加載Java的核心庫。它也不能代理給AppClassLoader,因為它是最頂層的類加載器。也就是說,雙親委派模型並不能解決這個問題
3.使用線程上下文類加載器(ContextClassLoader)加載
- 如果不做任何的設置,Java應用的線程的上下文類加載器默認就是AppClassLoader。在核心類庫使用SPI接口時,傳遞的類加載器使用線程上下文類加載器,就可以成功的加載到SPI實現的類。線程上下文類加載器在很多SPI的實現中都會用到。
- 通常我們可以通過Thread.currentThread().getClassLoader()和Thread.currentThread().getContextClassLoader()獲取線程上下文類加載器。
4、使用類加載器加載資源文件,比如jar包
類加載器除了加載class外,還有一個非常重要功能,就是加載資源,它可以從jar包中讀取任何資源文件,比如,ClassLoader.getResources(String name)方法就是用於讀取jar包中的資源文件
它的邏輯其實跟類加載的邏輯是一樣的,首先判斷父類加載器是否為空,不為空則委托父類加載器執行資源查找任務,直到BootstrapClassLoader,最后才輪到自己查找。而不同的類加載器負責掃描不同路徑下的jar包,就如同加載class一樣,最后會掃描所有的jar包,找到符合條件的資源文件。
轉載
鏈接:https://www.jianshu.com/p/0d196ad23915
來源:簡書