【Code皮皮虾】带你盘点双亲委派机制【原理、优缺点】,以及如何打破它?
文章目錄
- 🌊前言
- 什么是雙親委派機制?
- 雙親委派機制原理
- 優點
- 缺點
- 打破雙親委派機制?
- 前提知識:線程上下文類加載器
- 雙親委派出現之前
- JDBC打破雙親委派機制
- Tomcat
- 如何打破雙親委派機制?
- 1.自定義類加載器
- 2. 使用線程上下文類加載器
- 💖福利
- 🌊 Java入門到就業學習路線規劃
- 🌊 小白快速入門Python爬蟲路線
🌊前言
Code皮皮蝦 一個沙雕而又有趣的憨憨少年,和大多數小伙伴們一樣喜歡聽歌、游戲,當然除此之外還有寫作的興趣,emm…,日子還很長,讓我們一起加油努力叭🌈
👉話不多說,直達底部有粉絲專享福利!!!
什么是雙親委派機制?
說到雙親委派機制,那么我們需要先了解Java中的類加載器!
🌊Java中的類加載器主要分為以下四類:
啟動類加載器(BootStrap ClassLoader), 主要負責加載jre/lib/rt.jar相關的字節碼文件的。
擴展類加載器(Extension ClassLoader), 主要負載加載 jre/lib/ext/*.jar 這些jar包的。
應用程序類加載器(Application ClassLoader), 主要負責加載用戶自定義的類以及classpath環境變量所配置的jar包的。
自定義類加載器(UserClassLoader), 負責加載程序員指定的特殊目錄下的字節碼文件的。大多數情況下,自定義類加載器只需要繼承ClassLoader這個抽象類,重寫findClass()和loadClass()兩個方法即可。
雙親委派機制原理
優點
缺點
- 在某些場景下雙親委派制過于局限,所以有時候必須打破雙親委派機制來達到目的。例如:SPI機制
打破雙親委派機制?
打破雙親委派機制?
小伙伴:我看這雙親委派機制挺好的啊,為什么要打破呢。
皮皮蝦:哈哈,那就直接上實例講解叭。😉
前提知識:線程上下文類加載器
線程上下文類加載器(context class loader)是從 JDK 1.2 開始引入的。Java.lang.Thread中的方法 getContextClassLoader()和 setContextClassLoader(ClassLoader cl)用來獲取和設置線程的上下文類加載器。如果沒有通過 setContextClassLoader(ClassLoader cl)方法進行設置的話,線程將繼承其父線程的上下文類加載器。
Java 應用運行的初始線程的上下文類加載器是應用類加載器,在線程中運行的代碼可以通過此類加載器來加載類和資源。
線程上下文類加載器從根本解決了一般應用不能違背 雙親委派模式 的問題,使得java類加載體系顯得更靈活。上面所提到的問題正是線程上下文類加載器的拿手好菜。如果不做任何的設置,Java應用的線程上下文類加載器默認就是系統類加載器。因此,在 SPI 接口的代碼中使用線程上下文類加載器,就可以成功的加載到 SPI 實現的類。
雙親委派出現之前
由于雙親委派模型是在JDK1.2之后才被引入的,而在這之前已經有用戶自定義類加載器在用了。所以,這些是沒有遵守雙親委派原則的。
自定義類加載器加載一個類需要:繼承ClassLoader,重寫findClass,如果不想打破雙親委派模型,那么只需要重寫findClass;如果想打破雙親委派模型,那么就重寫整個loadClass方法,設定自己的類加載邏輯
JDBC打破雙親委派機制
使用SPI機制創建數據庫鏈接
前提是,只要mysql的jar包在類路徑中。
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mysql", "root", "0000");代碼執行之前,DriverManager會先被類加載器加載,因為java.sql.DriverManager類是位于rt.jar下面的 ,所以他會被啟動類加載器加載。
類加載時,會執行該類的靜態方法。其中有一段關鍵的代碼是:
ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);這段代碼,會嘗試加載classpath下面的所有實現了Driver接口的實現類。
那么,問題就來了。
DriverManager是被啟動類加載器加載的,那么在加載時遇到以上代碼,會嘗試加載所有Driver的實現類,但是這些實現類基本都是第三方提供的,第三方的類不能被啟動類加載器加載。
那么,怎么解決這個問題呢?
于是,就在JDBC中通過引入ThreadContextClassLoader(線程上下文加載器,默認情況下是AppClassLoader)的方式來使用應用程序類加載器 破壞了雙親委派原則。
我們深入到ServiceLoader.load方法就可以看到:
public static <S> ServiceLoader<S> load(Class<S> service) {//獲取線程上下文類加載器ClassLoader cl = Thread.currentThread().getContextClassLoader();return ServiceLoader.load(service, cl); }Tomcat
Tomcat是web容器,那么一個web容器可能需要部署多個應用程序。
不同的應用程序可能會依賴同一個第三方類庫的不同版本,但是不同版本的類庫中某一個類的全路徑名可能是一樣的。
如果采用默認的雙親委派類加載機制,那么是無法加載多個相同的類。
所以,Tomcat破壞雙親委派原則,提供隔離的機制,為每個web容器單獨提供一個WebAppClassLoader加載器。
Tomcat的類加載機制:為了實現隔離性,優先加載 Web 應用自己定義的類,所以沒有遵照雙親委派的約定,每一個應用自己的類加載器——WebAppClassLoader負責加載本身的目錄下的class文件,加載不到時再交給CommonClassLoader加載,這和雙親委派剛好相反。
前面3個類加載和默認的一致,CommonClassLoader、CatalinaClassLoader、SharedClassLoader和WebappClassLoader則是Tomcat自己定義的類加載器,它們分別加載/common/、/server/、/shared/*(在tomcat 6之后已經合并到根目錄下的lib目錄下)和/WebApp/WEB-INF/*中的Java類庫。
其中WebApp類加載器和Jsp類加載器通常會存在多個實例,每一個Web應用程序對應一個WebApp類加載器,每一個JSP文件對應一個Jsp類加載器。
如何打破雙親委派機制?
1.自定義類加載器
自定義類加載器加載一個類需要:繼承ClassLoader,重寫findClass,如果不想打破雙親委派模型,那么只需要重寫findClass;如果想打破雙親委派模型,那么就重寫整個loadClass方法,設定自己的類加載邏輯
想要打破即重寫的時候讓自己去加載不讓父加載器去加載
2. 使用線程上下文類加載器
public class Main {public static void main(String[] args) {ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();}}💖福利
公眾號干貨內容輸出,囊括Java、Python爬蟲、力扣題解、大廠面試題 四大系列,更有長時間總結的干貨資源分享
🌊 Java入門到就業學習路線規劃
關注底部公眾號回復: Java學習路線,即可領取全套資料
🌊 小白快速入門Python爬蟲路線
關注底部公眾號回復: 爬蟲學習路線,即可領取全套資料
總結
以上是生活随笔為你收集整理的【Code皮皮虾】带你盘点双亲委派机制【原理、优缺点】,以及如何打破它?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android中动画类别及优缺点,安卓培
- 下一篇: POJ 1658