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