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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

类加载器、双亲委派模型

發(fā)布時間:2024/10/14 编程问答 118 豆豆
生活随笔 收集整理的這篇文章主要介紹了 类加载器、双亲委派模型 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

目錄

1.簡介

2.類和類加載器

3.雙親委派模型

3.1 啟動類加載器:

3.2 擴展類加載器

3.3應(yīng)用程序類加載器

3.4? 類加載器的雙親委派模型(Parents Delegation Model)

雙親委派模型的工作過程:

好處:

實現(xiàn):

4.破壞雙親委派模型


1.簡介

虛擬機設(shè)計團隊把類加載階段的“通過一個類的全限定名來獲取描述此類的二進制字節(jié)流”這個動作。實現(xiàn)這個動作的代碼模塊稱為“類加載器”。

?

它是在JVM外部實現(xiàn)的,以便讓應(yīng)用程序自己決定如何獲取所需要的類。

2.類和類加載器

對于任何一個類,都需要由加載它的類加載器和這個類本身一同確立其在JVM中的唯一性。

每一個類加載器,都有一個獨立的類名稱空間。即,比較兩個類是否“相等”,只有在這兩個類是由同一個類加載器加載的前提下才有意義,否則,即使兩個類來源于同一個Class文件,被同一個虛擬機加載,只要加載它們的類加載器不同,那么這兩個類就必定不相等。

  • “相等”:包括代表類對象的equals()方法、isAssignableFromo()方法、isInstance()方法的返回結(jié)果,也包括使用instanceof關(guān)鍵字做對象所屬關(guān)系判定等情況。
  • 如果沒有注意到類加載器的影響,在某些情況下,可能會產(chǎn)生具有迷惑性的結(jié)果,如下代碼:
package CSDNpattern;import java.io.IOException; import java.io.InputStream;/* *類加載器與instanceof關(guān)鍵字演示 */ public class Test{public static void main(String[] args) throws Exception{ClassLoader myLoader=new ClassLoader() {@Overridepublic Class<?> loadClass(String name) throws ClassNotFoundException{try {String fileName=name.substring(name.lastIndexOf(".")+1)+".class";InputStream is=getClass().getResourceAsStream(fileName);if(is==null) {return super.loadClass(name);}byte[] b=new byte[is.available()];is.read(b);return defineClass(name,b,0,b.length);}catch(IOException e) {throw new ClassNotFoundException(name);}}};Object obj=myLoader.loadClass("CSDNpattern.Test").newInstance();System.out.println(obj.getClass());System.out.println(obj instanceof CSDNpattern.Test);} }

輸出:

上述代碼構(gòu)造了一個簡單的類加載器。

  • 可加載與自己同一路徑下的Class文件。
  • 使用這個類加載器加載了一個名為“CSDNpattern.Test”的類,并實例化了這個類的對象。
  • 輸出結(jié)果中,第一句表明這個類確實是“CSDNpattern.Test”;但第二句發(fā)現(xiàn)這個類和“CSDNpattern.Test”做所屬類型檢查的時候卻返回了false。
    • 因為虛擬機中存在了兩個Test類,一個室友系統(tǒng)應(yīng)用程序類加載器加載的,一個是由自定義的類加載器加載的。
    • 雖然都是來自同一個Class文件,但是是兩個獨立的類,做對象所屬類型檢查時結(jié)果自然為false。

3.雙親委派模型

從JVM角度來看,只存在兩種不同的類加載器:

  • 啟動類加載器(BootStrap ClasLoader):使用C++實現(xiàn),是虛擬機自身的一部分;
  • 所有其他的類加載器:由Java實現(xiàn),獨立于虛擬機外部,并且全都繼承自抽象類java.lang.Object。

從Java開發(fā)人員角度,還可以分的更細(xì),絕大部分Java程序都會用到一下3種系統(tǒng)提供的類加載器:

3.1 啟動類加載器:

  • 負(fù)責(zé)將存放在<JAVA_HOME>\lib目錄里的,或者被-Xbootclasspath參數(shù)指定的路徑中的,并且是虛擬機識別的(僅按照文件名識別,如rt.jar,名字不符合的類庫即使放在lib目錄中也不會被加載)類庫加載到虛擬機內(nèi)存中。
  • 它無法被Java程序直接引用。
  • 用戶在編寫自定義類加載器時,如果需要把加載請求為派給引導(dǎo)類加載器,納智捷使用null代替即可。如下代碼所示(提示錯)
package CSDNpattern;/** return the class loader for the class.* Some implementations may use null to present the bootstrap class loader.* this method will return null in such implementations * if this class was loaded by the bootstrap class loader.*/ public class Test{public ClassLoader getClassLoader() {ClassLoader cl=getClassLoader();if(cl==null)return null;SecurityManager sm=System.getSecurityManager();if(sm!=null) {ClassLoader ccl=ClassLoader.getCallerClassLoader();if(ccl!=null&&ccl!=cl&&!cl.isAncestor(ccl))sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);}}return cl; }

3.2 擴展類加載器

Extension ClassLoader

負(fù)責(zé)加載<JAVA_HOME>\lib\ext目錄中的,或者被java.ext.dirs系統(tǒng)變量所指定的路徑中的所有類庫,開發(fā)者可以使用擴展類加載器。

3.3應(yīng)用程序類加載器

Application ClassLoader

它是ClassLoader中的getSystemClassLoader()放的返回值,所有一般也稱為系統(tǒng)類加載器。

它負(fù)責(zé)加載用戶類路徑(ClassPath)上所指定的類庫,開發(fā)者可以直接使用這個類加載器。

如果應(yīng)用程序中沒有自定義過自己的類加載器,一般情況系下這個就是程序中的默認(rèn)的類加載器。

?

我們的應(yīng)用陳香菇都是由這3種類加載器相互配合進行加載的。

如有必要,還可以加入自定義的類加載器。

3.4? 類加載器的雙親委派模型(Parents Delegation Model)

這些類加載器的關(guān)系一般如下圖所示:

圖示的這種類加載器之間的這種層次關(guān)系,稱為類加載器的雙親委派模型(Parents Delegation Model)

雙親委派模型中要求除了頂層的啟動類加載器外,其余的類加載器都應(yīng)當(dāng)有自己的父類加載器。

這里的類加載器之間的父子關(guān)系一般不會以繼承(inheritance)的關(guān)系來實現(xiàn),而是使用組合(Composition)關(guān)系來復(fù)用父加載器的代碼。

類加載器的雙親委派模型在JDK1.2期間被引入并被廣泛應(yīng)用于之后幾乎所有的Java程序中。

但它并不是一個強制性的約束模型,而是Java設(shè)計者推薦給開發(fā)者的一種類加載器實現(xiàn)方式。

3.4.1 雙親委派模型的工作過程

  • 如果一個類加載器收到了類加載的請求,它首先不會自己去嘗試加載這個類,而是把這個請求為派給父類加載器去完成;
  • 每一個層次的類加載器都是如此;
  • 因此所有的加載請求最終都應(yīng)該傳送到頂層的啟動類加載器中;
  • 只有當(dāng)父加載器反饋自己無法完成這個加載請求(它的搜索范圍中沒有找到所需的類)時,子加載器才會嘗試自己去加載。
  • 3.4.2 好處

    Java類隨著它的類加載器一起舉杯了一種帶有優(yōu)先級的層次關(guān)系。

    例如,類java.lang.Object,它存放在rt.jar中,無論哪一個類加載器都要加載這個類,最終都是為派給處于模型最頂端的啟動類加載器進行加載。因此Object類在程序的各個類加載器環(huán)境中都是同一個類。

    相反,如果沒有使用這個模型,由各個類加載器自行去加載的話,如果用戶自己編寫了一個稱為java.lang.Object的類,并放在程序ClassPath中,那系統(tǒng)將會出現(xiàn)多個不同的Object類。Java類型體系中最基礎(chǔ)的行為也就無法保證,應(yīng)用程序也變得一片混亂。

    3.4.3 實現(xiàn)

    實現(xiàn)這個模型的代碼都集中在在java.lang.ClassLoader的loadClass()中。如下代碼所示:

    {//首先檢查請求的類是否已經(jīng)被加載過了Class c=findLoadedClass(name);if(c==null) {try {if(parent!=null)c=parent.loadClass(name,false);elsec=findBootStrapClassOrNull(name);}catch(ClassNotFoundException e) {//如果父類加載器 拋出ClassNotFoundException//說明父類加載器無法完成加載請求}if(c==null) {//在父類加載器無法完成加載的時候//再調(diào)用本身的findClass方法來進行類加載c=findClass(name);}}if(resolve) {resolveClass(c);} }

    邏輯:

  • 先檢查是否已經(jīng)被加載過,
  • 若沒有,則調(diào)用父類加載器的loadClass()方法;
  • 若父類加載器為空,則默認(rèn)使用啟動類加載器作為父類加載器。
  • 若父類加載器失敗,拋出ClassNotFoundException異常后,再調(diào)用自己的findClass()進行加載。
  • 4.破壞雙親委派模型

    雙親委派模型主要出現(xiàn)過3次較大規(guī)模的“被破壞”情況;

  • 在雙親委派模型出現(xiàn)之前,即JDK1.2發(fā)布之前。
  • 為了向前兼容,JDK1.2之后的java.lang.ClassLoader添加了一個新的protected方法findClass()。
  • JDK1.2之后不提倡用戶再去覆蓋loadClass(),而應(yīng)當(dāng)把自己的類加載器邏輯寫到findClass()中。
  • 在loadClass()的邏輯中,若父類加載失敗,則會調(diào)用自己的findClass()來完成加載。
  • 這樣就可以保證新寫出來的類加載器是符合雙親委派模型的。
  • 此模型自身的缺陷導(dǎo)致
  • 它很好地解決了各個類加載器的基礎(chǔ)類統(tǒng)一問題(越基礎(chǔ)的類由越上層的加載器進行加載)。
  • 基礎(chǔ)類:基礎(chǔ)的原因是它們總被作為用戶代碼調(diào)用的API。
  • 但是當(dāng)基礎(chǔ)類調(diào)用用戶代碼怎么辦?比如JNDI服務(wù)。
  • JNDI現(xiàn)在已是Java的標(biāo)準(zhǔn)服務(wù)。
  • 目的就是對資源進行集中種管理和查找。
  • 需要調(diào)用由獨立廠商實現(xiàn)并部署在應(yīng)用程序的ClassPath下的JNDI接口的提供者(SPI, service provider interface)的代碼。
  • 引入了線程上下文類加載器(Thread Context ClassLoader)來解決啟動類加載器不認(rèn)識這些代碼的問題。
  • 它可以通過國java.alng.Thread類的setContextClassLoader()進行設(shè)置。
  • 如果創(chuàng)建時還未設(shè)置,它將會從父線程中繼承一個;
  • 如果在應(yīng)用程序的全局范圍內(nèi)都沒有設(shè)置過的話,那這個類加載器就是應(yīng)用程序類的加載器。
  • Java中所有涉及SPI的加載動作基本上都采用這種方式:JNDI/JDBC/JCE/JAXB/JBI等
  • 由于用戶對程序動態(tài)性的追求導(dǎo)致
  • 動態(tài)性:代碼熱替換、模塊熱部署等,就是希望應(yīng)用程序能夠像計算機外設(shè)一樣,接上鼠標(biāo),U盤,不用重啟機器就能立即使用。
  • 整理自《深入理解Java虛擬機——JVM高級特性與最佳實踐》

    總結(jié)

    以上是生活随笔為你收集整理的类加载器、双亲委派模型的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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