日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【Code皮皮虾】带你盘点双亲委派机制【原理、优缺点】,以及如何打破它?

發(fā)布時(shí)間:2023/12/20 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【Code皮皮虾】带你盘点双亲委派机制【原理、优缺点】,以及如何打破它? 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

    • 🌊前言
    • 什么是雙親委派機(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ī)制原理

  • 如果一個(gè)類加載器收到了類加載請求,它并不會(huì)自己先去加載,而是把這個(gè)請求委托給父類的加載器去執(zhí)行。
  • 如果父類的加載器還存在其父類加載器,則進(jìn)一步向上委托,依次遞歸請求最終達(dá)到頂層的啟動(dòng)類加載器
  • 如果父類加載器可以完成類加載任務(wù),就成功返回,倘若父類加載器無法完成此加載任務(wù),子加載器才會(huì)嘗試自己去加載,這就是雙親委派機(jī)制。
  • 優(yōu)點(diǎn)

  • 避免類的重復(fù)加載
  • 保護(hù)程序安全,防止核心API被隨意篡改
  • 缺點(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)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。