成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

外婆問我:什么是雙親委派原則?

開發(fā) 前端
我這篇文章將對(duì) Java 類加載器的雙親委派加載原理進(jìn)行闡述,并結(jié)合實(shí)例程序深究類的雙親委派加載機(jī)制,大家徹底了解掌握類加載原理,清楚了類加載原理后,碰到上述類似問題就能快速解決,并在后續(xù)開發(fā)中避免類似問題。

 [[384140]]

本文轉(zhuǎn)載自微信公眾號(hào)「三太子敖丙」,作者三太子敖丙。轉(zhuǎn)載本文請(qǐng)聯(lián)系三太子敖丙公眾號(hào)。

我敢打賭大家在開發(fā)過程中經(jīng)常碰到一些類加載的問題,比如:

ClassNotFoundException

  1. Cause: java.lang.ClassNotFoundException: Cannot find class: com.cc.A 

NoClassDefFoundError

  1. Cause: java.lang.NoClassDefFoundError: Cannot find class: com.cc.A 

上述問題均和java類加載有關(guān),如果不清楚JVM中類加載的原理,上述問題會(huì)讓人郁悶至極,僥幸在網(wǎng)上找到解決方案也只是暫時(shí)解決問題,后續(xù)在另外的場(chǎng)景中碰到又會(huì)繼續(xù)懵逼。

我這篇文章將對(duì) Java 類加載器的雙親委派加載原理進(jìn)行闡述,并結(jié)合實(shí)例程序深究類的雙親委派加載機(jī)制,大家徹底了解掌握類加載原理,清楚了類加載原理后,碰到上述類似問題就能快速解決,并在后續(xù)開發(fā)中避免類似問題。

什么是Java類加載?

java類加載器負(fù)責(zé)將編譯好的 Java class 件加載到 Java 虛擬機(jī)(JVM)中的運(yùn)行時(shí)數(shù)據(jù)區(qū)中,供執(zhí)行引擎調(diào)用。

java類加載在JVM體系結(jié)構(gòu)中的位置如圖所示:

jvm體系結(jié)構(gòu)原圖

 

沒有類加載機(jī)制,編寫的java程序就沒法在JVM中運(yùn)行,因此掌握java類加載是非常重要的。

JVM類加載層級(jí)關(guān)系

執(zhí)行java程序時(shí),會(huì)啟動(dòng)一個(gè)JVM進(jìn)程,JVM在啟動(dòng)時(shí)會(huì)做一些初始化操作,比如獲取系統(tǒng)參數(shù)等等,然后創(chuàng)建一個(gè)啟動(dòng)類加載器,用于加載JVM運(yùn)行時(shí)必須的一些類到內(nèi)存中,同時(shí)也會(huì)創(chuàng)建其他兩個(gè)類加載器擴(kuò)展類加載器和系統(tǒng)類加載器。

啟動(dòng)類加載器、擴(kuò)展類加載器和系統(tǒng)類加載器之間的關(guān)系如下圖所示:

jvm內(nèi)置classLoader

 

  • **啟動(dòng)類加載器:**java虛擬機(jī)啟動(dòng)后創(chuàng)建的第一個(gè)類加載器,由C++語(yǔ)言實(shí)現(xiàn),所以我們?cè)趈ava代碼中查看其信息時(shí),看到的均為null。
  • 擴(kuò)展類加載器:由啟動(dòng)類加載器加載,并將擴(kuò)展類加載器中的parent的值設(shè)置為null(表示指向啟動(dòng)類加載器),同時(shí)繼承自URLClassLoader。
  • 系統(tǒng)類加載器:由啟動(dòng)類加載器加載,并將系統(tǒng)類加載期中的parent的值設(shè)置為上述創(chuàng)建的擴(kuò)展類加載器。,同時(shí)繼承自URLClassLoader。

在代碼中可以通過如下方式查看類加載中的parent指向:

代碼查看類加載器的parent

 

注意:這里的parent不是java的繼承機(jī)制,而是類加載器中的一個(gè)實(shí)例屬性,用于在類加載時(shí)的委托對(duì)象,parent屬性定義在其所繼承的ClassLoader中,定義如下所示。

  1. public abstract class ClassLoader { 
  2.    .................... 
  3.     // The parent class loader for delegation 
  4.     private final ClassLoader parent; 

JVM類加載的默認(rèn)加載路徑

每種類型的類加載器默認(rèn)都會(huì)有自己的加載路徑,啟動(dòng)類加載器、擴(kuò)展類加載器和系統(tǒng)類加載器的默認(rèn)加載路徑如下圖所示:

三種類加載器的加載路徑

 

如上圖所示:

1、啟動(dòng)類加載器(BootClassLoader)由C++語(yǔ)言編寫,負(fù)責(zé)在JVM啟動(dòng)時(shí)加載jdk自身的一些核心class類(jar包形式)到JVM中,加載時(shí)尋找資源的路徑由只讀系統(tǒng)屬性:”sun.boot.class.path“ 指定,一般為:”JAVA_HOME/jre/classes“目錄(在該目錄下只能放class文件,jar包形式文件不生效)。

查看啟動(dòng)類加載類加載路徑可以通過獲取系統(tǒng)屬性:”sun.boot.class.path“進(jìn)行查看,如圖所示:

lancher中設(shè)置啟動(dòng)類加載路徑

啟動(dòng)類加載器加載路徑

 

2、擴(kuò)展類加載器(ExtClassLoader),負(fù)責(zé)加載位于系統(tǒng)屬性:"java.ext.dirs"指向的目錄下加載class文件(jar包或者直接class文件形式)到JVM中,比如通常ext類加載路徑為:”$JAVA_HOMEx/jre/lib/ext“ 。

支持在JVM啟動(dòng)之前進(jìn)行修改路徑,運(yùn)行中修改路徑不生效,擴(kuò)展類路徑中僅支持jar包的加載。

查看擴(kuò)展類加載器的類加載路徑可以通過獲取系統(tǒng)屬性:”java.ext.dirs“進(jìn)行查看或向上轉(zhuǎn)型為URLClassLoader(上面說擴(kuò)展類加載器繼承自URLClassLoader),查看位于父類URLClassLoader中urls屬性的方式進(jìn)行查看,如圖所示:

擴(kuò)展類加載器路徑

 

3、系統(tǒng)類加載器(AppClassLoader),負(fù)責(zé)加載應(yīng)用classpath路徑下的class文件(jar包或者直接class文件形式)到JVM中,當(dāng)系統(tǒng)中沒有設(shè)置classpath路徑時(shí),默認(rèn)加載當(dāng)前路徑下的class文件。

查看系統(tǒng)類加載器的類加載路徑可以通過獲取系統(tǒng)屬性:”java.class.path“進(jìn)行查看或向上轉(zhuǎn)型為URLClassLoader上面說擴(kuò)展類加載器繼承自URLClassLoader),查看位于父類URLClassLoader中urls屬性的方式進(jìn)行查看,如圖所示:

系統(tǒng)類加載路徑

 

JVM類加載雙親委托機(jī)制

JVM加載class類文件到虛擬機(jī)時(shí),默認(rèn)首先采用系統(tǒng)類加載器去加載用到的class類,采用的是雙親委托加載機(jī)制。

所謂雙親委托,顧名思義,就是當(dāng)前類加載器(以系統(tǒng)類加載器為例)在加載一個(gè)類時(shí),委托給其雙親(注意這里的雙親指的是類加載器中parent屬性指向的類加載器)先進(jìn)行加載。

雙親類加載器在加載時(shí)同樣委托給自己的雙親,如此反復(fù),直到某個(gè)類加載器沒有雙親為止(通常情況下指雙親為null,也即為當(dāng)前的雙親為擴(kuò)展類加載器,其parent為啟動(dòng)類加載器),然后開始在依次在各自的類路徑下尋找、加載class類。

如下圖所示:

雙親委派

 

雙親委托加載實(shí)例實(shí)例

采用JDK版本

  1. java version "1.8.0_261" Java(TM) SE Runtime Environment (build 1.8.0_261-b12) Java HotSpot(TM) 64-Bit Server VM (build 25.261-b12, mixed mode) 

本實(shí)例涉及到兩個(gè)類:TestMain.java 和 A.java,期中TestMain為啟動(dòng)類,在啟動(dòng)類中調(diào)用類A中的方法執(zhí)行進(jìn)行輸出,分別輸出啟動(dòng)類和被依賴類的類加載器信息,類定義如下所示:

A_java


TestMain

 

我們將兩個(gè)java文件拷貝到某個(gè)目錄下,在我本地比如放在E:\java_app目錄下,windows下打開命令行窗口,切換到E:\java_app,對(duì)當(dāng)前java文件進(jìn)行編譯,執(zhí)行命令javac TestMain.java。

此時(shí)會(huì)在當(dāng)前目錄下生產(chǎn)對(duì)應(yīng)的class文件(這里只需要對(duì)TestMain執(zhí)行編譯命令,因?yàn)門estMain依賴了A,所以Jdk編譯器就會(huì)自動(dòng)先去編譯依賴的A),如圖所示:

編譯命令

 

接下來我們將觀察java類加載機(jī)制是怎樣實(shí)現(xiàn)雙親委托加載的。

委托給擴(kuò)展類加載器加載

由于擴(kuò)展類在自身類路徑下加載只支持尋找jar包的方式,因此我們通過工具將A.class文件打包進(jìn)A.jar。

然后將A.jar放置到擴(kuò)展類加載路徑:$JAVA_HOME/jre/lib/ext,同時(shí)保留當(dāng)前目錄中的A.class文件。如圖所示:

擴(kuò)展委派

 

此時(shí)在當(dāng)前目錄:E:\java_app下仍然保留有A.class文件,在擴(kuò)展類加載器路徑下多了一個(gè)包含了A.class的A.jar文件,在當(dāng)前目錄下執(zhí)行java命令執(zhí)行TestMain,命令為:java TestMain,輸出如下所示:

擴(kuò)展委派結(jié)果

 

由上圖輸出結(jié)果可知,class A雖然在系統(tǒng)類加載器的加載路徑中,但由于類加載的委托機(jī)制,A首先將由系統(tǒng)類加載器委托給其雙親擴(kuò)展類加載器進(jìn)行加載,剛好在擴(kuò)展類加載器的加載路徑中包含了A.class(包含在A.jar中),所以A最終由擴(kuò)展類加載器進(jìn)行了加載。

委托給啟動(dòng)類加載器進(jìn)行加載

通常情況下,普通類的加載不應(yīng)該委托給啟動(dòng)類加載器進(jìn)行加載,因?yàn)榍懊嬲f過啟動(dòng)類加載器由C++實(shí)現(xiàn),在java虛擬機(jī)啟動(dòng)時(shí)生成的,在java環(huán)境中獲取她的信息均為null。

本實(shí)例為了探究類加載的雙親委托機(jī)制,所以特意將構(gòu)造一個(gè)將普通類委托給其加載的場(chǎng)景。

前面在講到啟動(dòng)類加載器加載路徑時(shí)指出了啟動(dòng)類加載器的加載路徑由只讀系統(tǒng)屬性”sun.boot.class.path“ 指定,且僅支持加載該目錄下固定的jar文件。

在jdk8中還有”$JAVA_HOME/jre/classes“目錄也是啟動(dòng)類加載器加載的路徑(該路徑默認(rèn)可能不存在,可以手工創(chuàng)建一個(gè)),在該目錄下只能放class文件,jar包形式文件不生效。

因此,本實(shí)例程序?qū)?dāng)前目錄下的A.class文件拷貝到啟動(dòng)類加載器的類路徑:”$JAVA_HOME/jre/classes“中,同時(shí)保留當(dāng)前目錄中的A.class文件,也保留擴(kuò)展類加載器類路徑中的A.jar。

類存放路徑如圖所示:

委派啟動(dòng)

 

在當(dāng)前目錄:E:\java_app目錄下執(zhí)行命令運(yùn)行TestMain,命令為:java TestMain,輸出如下所示:

委派啟動(dòng)結(jié)果

 

由上圖輸出結(jié)果可知,class A雖然在系統(tǒng)類加載器的加載路徑中,也存在擴(kuò)展類加載器的加載路徑中,但由于類加載的委托機(jī)制,A首先將由系統(tǒng)類加載器委托給其雙親擴(kuò)展類加載器進(jìn)行加載。

擴(kuò)展類加載器又會(huì)繼續(xù)進(jìn)行委托加載(實(shí)際上因?yàn)閿U(kuò)展類加載器的parent:?jiǎn)?dòng)類加載器為null,所以此時(shí)的委托動(dòng)作實(shí)際上就是去啟動(dòng)類加載器的加載路徑中尋找class A),最終由啟動(dòng)類加載進(jìn)行了A的加載。

雙親委托加載方向

類加載器在加載類時(shí),只能向上遞歸委托其雙親進(jìn)行類加載,而不可能從雙親再反向委派當(dāng)前類加載器來進(jìn)行類加載。

在中國(guó)象棋中,卒子過河之后的行走軌跡永遠(yuǎn)只能是前進(jìn)或者左右平移,可以很形象的比作雙親委托類加載的這種方向性。

  • 卒子過河比喻當(dāng)前類加載器委派其雙親加載了某個(gè)類。這個(gè)類的后續(xù)依賴的加載已經(jīng)和當(dāng)前類加載器沒有關(guān)系。
  • 過河之后的卒子只能前進(jìn),表示雙親在加載類的依賴類時(shí),只能繼續(xù)遞歸進(jìn)行雙親委派。
  • 左右平移表示雙親在遞歸雙親委派加載失敗后,在雙親類加載器自己的加載路徑中進(jìn)行加載。

為了表明委派具有方向性,我們繼續(xù)拿上面的TestMain.class和A.class兩個(gè)類做實(shí)驗(yàn)。

上述委托實(shí)例中我們的場(chǎng)景時(shí)是:TestMain中依賴了A,我們將A通過雙親委托方式進(jìn)行了加載,本次實(shí)驗(yàn)中,我們將TestMain委托給雙親加載。

參照上述的操作步驟,將TestMain.class打進(jìn)TestMain.jar中,放到擴(kuò)展類加載器的加載路徑中,同時(shí)也保留TestMain.class到當(dāng)前目錄,如下圖所示:

委派加載順序1

 

切換到當(dāng)前應(yīng)用目錄,執(zhí)行java命令運(yùn)行程序:java TestMain,執(zhí)行結(jié)果如下所示:

委派順序執(zhí)行結(jié)果

 

如上圖所示,出現(xiàn)錯(cuò)誤了,TestMain被擴(kuò)展類加載器加載了,依賴的A卻沒有能被加載到。

原因就是上述說的委派加載具有方向性導(dǎo)致的:

1、運(yùn)行java命令執(zhí)行TestMain程序時(shí),系統(tǒng)類加載器準(zhǔn)備加載TestMain,根據(jù)雙親委派機(jī)制,先委派給其雙親進(jìn)行加載,最后,雙親擴(kuò)展類加載器在其加載路徑中的TestMain.jar中找到了TestMain.class,完成了TestMain的加載。

2、TestMain中依賴了A,此時(shí),會(huì)根據(jù)加載了TestMain的類加載器:擴(kuò)展類加載器去加載A,加載方式根據(jù)委托機(jī)制遞歸委托給雙親加載,擴(kuò)展類加載器的雙親為啟動(dòng)類加載器,在啟動(dòng)類加載器的加載路徑中不存在A,加載失敗,此時(shí)由擴(kuò)展類加載器在自己的加載路徑中加載A,也因?yàn)榧虞d路徑中沒有A.class存在,A.class存在于系統(tǒng)類加載器的加載路徑中,但是擴(kuò)展類加載器不會(huì)再返回去委托系統(tǒng)類加載器進(jìn)行加載,所以直接拋出加載失敗異常,出現(xiàn)了上述的錯(cuò)誤。

總結(jié)這次大致介紹了java的類加載在整個(gè)JVM中的作用,詳細(xì)介紹了JVM中的啟動(dòng)類加載器、擴(kuò)展類加載器和系統(tǒng)類加載器三者之間的關(guān)系,并結(jié)合實(shí)例著重介紹了類加載的雙親委派加載原理,理解java的雙親委派加載原理之后,就能在后續(xù)的程序開發(fā)設(shè)計(jì)中在程序的動(dòng)態(tài)設(shè)計(jì)這塊掌握更多高級(jí)技能,開發(fā)出更加優(yōu)秀的產(chǎn)品。

 

責(zé)任編輯:武曉燕 來源: 三太子敖丙
相關(guān)推薦

2023-12-06 12:11:43

類加載器雙親委派模型

2023-02-03 07:24:49

雙親委派模型

2023-08-04 08:53:42

2024-06-24 08:24:57

2025-04-07 04:25:00

JDBCAPI加載器

2012-06-25 10:05:10

程序員

2023-10-30 01:02:56

Java類類加載器雙親委派

2021-11-23 10:50:29

關(guān)聯(lián)規(guī)則推薦推薦系統(tǒng)開發(fā)

2021-11-15 12:45:44

協(xié)同過濾算法架構(gòu)

2024-07-05 09:31:37

2021-11-12 11:51:03

基于內(nèi)容的推薦查詢推薦

2021-05-12 16:27:55

Java雙親模型

2024-03-27 09:15:27

2020-03-18 09:31:47

設(shè)計(jì)模式軟件

2020-03-30 17:20:54

B+樹SQL索引

2010-01-22 10:36:25

C++語(yǔ)言

2023-01-04 00:09:31

2024-12-04 09:01:55

引導(dǎo)類加載器C++

2021-01-06 09:51:19

類加載器雙親委派模型

2021-03-03 12:19:20

原型原型鏈JavaScript
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 国产精品国产三级国产aⅴ中文 | 久久国产精品网站 | 国产成人精品一区二区三区在线观看 | 一区二区三区视频播放 | 自拍偷拍视频网 | 久草热线| 日本成人在线观看网站 | 精品欧美激情在线观看 | 欧美一区永久视频免费观看 | 中文字幕一区二区三区不卡 | 日本天天操 | 日韩精品中文字幕一区二区三区 | 日本不卡一区二区三区 | 精品少妇v888av | 日韩国产中文字幕 | 综合九九| 国产精品一区二区三 | 美女高潮网站 | 啪啪精品 | 亚洲国产欧美一区 | 久久国产精品久久久久久久久久 | 日本五月婷婷 | 人人射人人插 | 久久精品日产第一区二区三区 | 一区二区三区四区电影 | 久在线精品视频 | 欧美精品 在线观看 | 一区二区福利视频 | 国产一区二区三区久久久久久久久 | 91久久精品国产91久久 | 日本一区二区不卡 | 国产真实乱对白精彩久久小说 | 国产高清视频在线 | 黄色片在线网站 | 黄色精品| 久久一区 | 国产精品区二区三区日本 | 亚洲va欧美va人人爽午夜 | 成人精品久久 | 国产精品美女一区二区 | 久久一区二区视频 |