白話說Java虛擬機(jī)原理系列【第三章】:類加載器詳解-創(chuàng)新互聯(lián)

文章目錄
        • jvm.dll
        • BootstrapLoader:裝載系統(tǒng)類
        • ExtClassLoader:裝載擴(kuò)展類
        • AppClassLoader:裝載自定義類
        • 雙親委派模型
        • 類加載器加載類的方式
        • 類加載器特性
        • 類加載器加載字節(jié)碼到JVM的過程
        • 自定義/第三方類加載器
        • `類加載器加載字節(jié)碼到哪?`
        • Class類對(duì)象
        • 破壞雙親委派機(jī)制:spi機(jī)制


公司專注于為企業(yè)提供成都網(wǎng)站設(shè)計(jì)、成都網(wǎng)站建設(shè)、微信公眾號(hào)開發(fā)、商城開發(fā),小程序設(shè)計(jì),軟件按需網(wǎng)站設(shè)計(jì)等一站式互聯(lián)網(wǎng)企業(yè)服務(wù)。憑借多年豐富的經(jīng)驗(yàn),我們會(huì)仔細(xì)了解各客戶的需求而做出多方面的分析、設(shè)計(jì)、整合,為客戶設(shè)計(jì)出具風(fēng)格及創(chuàng)意性的商業(yè)解決方案,成都創(chuàng)新互聯(lián)更提供一系列網(wǎng)站制作和網(wǎng)站推廣的服務(wù)。

前導(dǎo)說明:
本文基于《深入理解Java虛擬機(jī)》第二版和個(gè)人理解完成,
以大白話的形式期望能用大家都看懂的描述講清楚虛擬機(jī)內(nèi)幕,
后續(xù)會(huì)增加基于《深入理解Java虛擬機(jī)》第三版內(nèi)容,并進(jìn)行二個(gè)版本的對(duì)比

JVM基本結(jié)構(gòu)圖


jvm.dll

首次要執(zhí)行JAVA程序就都需要啟動(dòng)JVM虛擬機(jī),由java.exe負(fù)責(zé)獲取JRE目錄位置中的jvm.dll動(dòng)態(tài)鏈接庫,然后加載運(yùn)行此庫,即JVM虛擬機(jī)。

BootstrapLoader:裝載系統(tǒng)類
  • JVM啟動(dòng)初始化后,第一創(chuàng)建的類加載器為BootstrapLoader,此由C++語言實(shí)現(xiàn),加載運(yùn)行后它會(huì)加載Launcher.class字節(jié)碼文件,Launcher內(nèi)部有ExtClassLoader、AppClassLoader兩個(gè)內(nèi)部類,它會(huì)先創(chuàng)建ExtClassLoader并將它的parent設(shè)置成null,然后再創(chuàng)建AppClassLoader,并將它的parent設(shè)置成ExtClassLoader。至此完成了BootstrapLoader的初始化,同時(shí)也完成了類加載器的初始化。
  • BootstrapLoader加載器負(fù)責(zé)加載JAVA安裝目錄中的類,即核心JAVA API對(duì)應(yīng)的類。如JRE目錄下的rt.jar、charsets.jar等,BootstrapLoader由C++編寫實(shí)現(xiàn),由于不是JAVA體系,所以JVM選擇了透明化該類,所以ExtClassLoader的parent設(shè)置成了null,其實(shí)代表的就是ExtClassLoader的parent為BootstrapLoader,只不過透明化了這個(gè)C++實(shí)現(xiàn)的類。
ExtClassLoader:裝載擴(kuò)展類

負(fù)責(zé)加載JRE安裝目錄的"\lib\ext"目錄下的類。

AppClassLoader:裝載自定義類
  • 負(fù)責(zé)加載自己開發(fā)的類,就是環(huán)境變量中配置的"."點(diǎn)對(duì)應(yīng)的目錄了。其實(shí)是java.class.path對(duì)應(yīng)的目錄,即CLASSPATH目錄
  • 默認(rèn)情況下使用AppClassLoader裝載應(yīng)用程序中的類。
雙親委派模型

問題:有這么寫類加載器,實(shí)際中我們要用哪個(gè)最合理呢?

這就要看一下他的運(yùn)行機(jī)制:雙親委派機(jī)制

原理:就是如果有類加載的需求時(shí),加載器先通過parent去嘗試在對(duì)應(yīng)的路徑下加載,如果parent得不到類文件,再由子加載器去加載,直到加載到文件。比如一個(gè)自定義的類,加載時(shí),先由BootstrapLoader加載,加載不到再由ExtClassLoader加載,加載不到最后才由AppClassLoader進(jìn)行加載。這就是委托模型機(jī)制,分工明確,各司其職。

原因:出于安全、保護(hù)JVM考慮,比如我自己實(shí)現(xiàn)了一個(gè)較差的String類,如果沒有此機(jī)制,那么就可以隨意加載到JVM,那可能導(dǎo)致一些問題,有了此機(jī)制,那么String永遠(yuǎn)都是有BootstrapLoader加載,且加載的是JAVA提供的核心類庫中的類。

證明:要想證明累的加載過程是不是對(duì),只需建一個(gè)main方法,運(yùn)行一下,只不過增加一個(gè)java的啟動(dòng)參數(shù):設(shè)置虛擬機(jī)參數(shù)"-XX:+TraceClassLoading"來獲取類加載信息,信息將會(huì)打印在控制臺(tái)或log。

類加載器加載類的方式
  • 隱式裝載:程序運(yùn)行過程中碰到new關(guān)鍵字,則會(huì)先裝載對(duì)應(yīng)的類。
  • 顯示裝載:通過Class.forName()等類似方法顯示的調(diào)用裝載。

類加載途徑:虛擬機(jī)對(duì)類加載的規(guī)范很模糊,即最終加載成二進(jìn)制流,但是二進(jìn)制流從哪來沒有規(guī)定,所以可以有如下途徑獲取類的字節(jié)碼文件:

  • ①從zip包中獲取,這就是以后jar、ear、war格式的基礎(chǔ)
  • ②從網(wǎng)絡(luò)中獲取,典型應(yīng)用就是Applet
  • ③運(yùn)行時(shí)計(jì)算生成,典型應(yīng)用就是動(dòng)態(tài)代理技術(shù)
  • ④由其他文件生成,典型應(yīng)用就是JSP,即由JSP生成對(duì)應(yīng)的.class文件
  • ⑤從數(shù)據(jù)庫中讀取,這種場景比較少見
類加載器特性

對(duì)于任意一個(gè)類,都需要由加載它的類加載器和這個(gè)類本身一同確立其在Java虛擬機(jī)中的唯一性,每一個(gè)類加載器,都擁有一個(gè)獨(dú)立的類名稱空間。這句話表達(dá)地再簡單一點(diǎn)就是:比較兩個(gè)類是否"相等",只有在這兩個(gè)類是由同一個(gè)類加載器加載的前提下才有意義,否則即使這兩個(gè)類來源于同一個(gè).class文件,被同一個(gè)虛擬機(jī)加載,只要加載它們的類加載器不同,這兩個(gè)類必定不相等。

類加載器加載字節(jié)碼到JVM的過程

在這里插入圖片描述
此處我們忽略“使用”和“卸載”兩個(gè)過程,”使用“就是我們代碼中實(shí)現(xiàn)的功能,卸載將會(huì)交由GC處理。

1.裝載:查找和導(dǎo)入class字節(jié)碼文件到運(yùn)行時(shí)數(shù)據(jù)區(qū)的方法區(qū)。
2.鏈接:

檢查:檢查載入的class文件數(shù)據(jù)的正確性。
準(zhǔn)備:給類的靜態(tài)變量分配存儲(chǔ)空間,存于方法區(qū)。此過程還會(huì)對(duì)(虛)方發(fā)表完成初始化。
解析:將符號(hào)引用轉(zhuǎn)成直接引用,常量池解析。

3.初始化:對(duì)靜態(tài)變量、靜態(tài)代碼塊(即靜態(tài)方法)執(zhí)行初始化工作。
最后通過加載器創(chuàng)建Class類對(duì)象存于堆,并指向方法區(qū)該類的存儲(chǔ)區(qū)域。

自定義/第三方類加載器

類加載器可以由第三方自己實(shí)現(xiàn)一些特殊的功能。

  • ClassLoader抽象類:類加載由此開始,會(huì)調(diào)用它的loadClass方法,查看源碼可以發(fā)現(xiàn)雙親委派的具體實(shí)現(xiàn),以及各個(gè)類加載器加載的目錄對(duì)應(yīng)的環(huán)境變量具體是哪個(gè)。
  • 自定義加載器:如果我們要保留雙親委派機(jī)制,那么需要繼承ClassLoader類并實(shí)現(xiàn)findClass方法(從源碼可知這個(gè)方法默認(rèn)是空實(shí)現(xiàn),為自定義準(zhǔn)備的擴(kuò)展方法)來加載jvm默認(rèn)加載器處理范圍之外的類,如果我們想更廣范圍的加載類,比如不讓AppClassLoader生效,那么只能自己重寫ClassLoader類的loadClass方法了。
類加載器加載字節(jié)碼到哪?

類加載器加載字節(jié)碼文件到運(yùn)行時(shí)數(shù)據(jù)區(qū)的方法區(qū)中,然后再完成一系列字節(jié)碼文件的解析(常量池解析等),最后會(huì)創(chuàng)建一個(gè)與類文件相關(guān)的對(duì)象存入堆(即類對(duì)象)并通過指針指向方法區(qū)當(dāng)前類的定義(指針指的是堆中的對(duì)象頭中會(huì)有一個(gè)引用指向方法區(qū)類字節(jié)碼定義的位置,方法區(qū)章節(jié)會(huì)詳細(xì)講解,此處知道即可)。

Class類對(duì)象
  • 類加載器加載class文件后,最終都會(huì)創(chuàng)建一個(gè)Class類的對(duì)象存于堆中,用于和方法區(qū)中的class文件內(nèi)容關(guān)聯(lián)。
  • Class類沒有public的構(gòu)造方法,Class類的對(duì)象是在裝載類時(shí)由JVM通過調(diào)用類裝載器中的defineClass()方法自動(dòng)構(gòu)建的。
  • 方法區(qū)中也會(huì)保存加載當(dāng)前class文件的加載器信息,因?yàn)镃lass類的對(duì)象是由加載器創(chuàng)建的,所以通過Class類對(duì)象可以得知用的哪個(gè)加載器。
破壞雙親委派機(jī)制:spi機(jī)制

上邊說了,雙親委派的作用就是安全,保障jdk的類只有自己的加載器能加載,但是有些時(shí)候我們需要讓我們自己提供的類被加載,該怎么辦呢?

幾種方法: 比如

  • 就是重寫源碼,這個(gè)不太可取
    就是重寫類加載器的loadClass方法,以此改變類加載的方式;
  • 通過jdk提供的spi方式,我們提供自己的實(shí)現(xiàn)類,這樣通過spi的配置,就可以成功通過雙親委派來加載到我們提供的類了。

簡單介紹SPI: spi的方法就是定義自己的實(shí)現(xiàn)類,比如數(shù)據(jù)庫驅(qū)動(dòng)Driver接口的實(shí)現(xiàn)類,然后將實(shí)現(xiàn)類放到META-INF/services目錄的Driver全名的配置文件中,這樣就可以了,當(dāng)然使用的時(shí)候要用ServiceLoader來加載具體的實(shí)現(xiàn)類(spi內(nèi)容可以到dubbo章節(jié)的講解中學(xué)習(xí))。

你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購,新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧

標(biāo)題名稱:白話說Java虛擬機(jī)原理系列【第三章】:類加載器詳解-創(chuàng)新互聯(lián)
文章源于:http://www.muchs.cn/article4/djjpie.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供微信小程序、面包屑導(dǎo)航網(wǎng)頁設(shè)計(jì)公司、響應(yīng)式網(wǎng)站商城網(wǎng)站、全網(wǎng)營銷推廣

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

綿陽服務(wù)器托管