1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        ClassLoader 類加載器模型

        共 6499字,需瀏覽 13分鐘

         ·

        2021-10-26 21:22

        一、 類加載器

        ClassLoader即常說的類加載器,其功能是用于從Class文件加載所需的類,主要場景用于熱部署、代碼熱替換等場景。

        系統(tǒng)提供3種類加載器:Bootstrap ClassLoader、Extension ClassLoader、Application ClassLoader

        1.1 Bootstrap ClassLoader

        啟動類加載器,一般由C++實(shí)現(xiàn),是虛擬機(jī)的一部分。該類加載器主要職責(zé)是將JAVA_HOME路徑下的\lib目錄中能被虛擬機(jī)識別的類庫(比如rt.jar)加載到虛擬機(jī)內(nèi)存中。Java程序無法直接引用該類加載器

        1.2 Extension ClassLoader

        擴(kuò)展類加載器,由Java實(shí)現(xiàn),獨(dú)立于虛擬機(jī)的外部。該類加載器主要職責(zé)將JAVA_HOME路徑下的\lib\ext目錄中的所有類庫,開發(fā)者可直接使用擴(kuò)展類加載器。該加載器是由sun.misc.Launcher$ExtClassLoader實(shí)現(xiàn)。

        1.3 Application ClassLoader

        應(yīng)用程序類加載器,該加載器是由sun.misc.Launcher$AppClassLoader實(shí)現(xiàn),該類加載器負(fù)責(zé)加載用戶類路徑上所指定的類庫。開發(fā)者可通過ClassLoader.getSystemClassLoader()方法直接獲取,故又稱為系統(tǒng)類加載器。當(dāng)應(yīng)用程序沒有自定義類加載器時(shí),默認(rèn)采用該類加載器。

        ClassLoader.java

         1public?static?ClassLoader?getSystemClassLoader()?{
        2????initSystemClassLoader();?//初始化系統(tǒng)類加載器?【見下文】
        3????if?(scl?==?null)?{
        4????????return?null;
        5????}
        6????SecurityManager?sm?=?System.getSecurityManager();
        7????if?(sm?!=?null)?{
        8????????ClassLoader?ccl?=?getCallerClassLoader();
        9????????if?(ccl?!=?null?&&?ccl?!=?scl?&&?!scl.isAncestor(ccl))?{
        10????????????sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
        11????????}
        12????}
        13????return?scl;
        14}

        系統(tǒng)類加載器初始化

         1private?static?synchronized?void?initSystemClassLoader()?{
        2????if?(!sclSet)?{
        3????????if?(scl?!=?null)
        4????????????throw?new?IllegalStateException("recursive?invocation");
        5????????sun.misc.Launcher?l?=?sun.misc.Launcher.getLauncher();
        6????????if?(l?!=?null)?{
        7????????????Throwable?oops?=?null;
        8????????????scl?=?l.getClassLoader();
        9????????????try?{
        10????????????????scl?=?AccessController.doPrivileged(
        11????????????????????new?SystemClassLoaderAction(scl));
        12????????????}?catch?(PrivilegedActionException?pae)?{
        13????????????????oops?=?pae.getCause();
        14????????????????if?(oops?instanceof?InvocationTargetException)?{
        15????????????????????oops?=?oops.getCause();
        16????????????????}
        17????????????}
        18????????????if?(oops?!=?null)?{
        19????????????????if?(oops?instanceof?Error)?{
        20????????????????????throw?(Error)?oops;
        21????????????????}?else?{
        22????????????????????throw?new?Error(oops);
        23????????????????}
        24????????????}
        25????????}
        26????????sclSet?=?true;
        27????}
        28}

        二、雙親委派模型

        ClassLoader的雙親委派模型中,各個(gè)ClassLoader之間的關(guān)系是通過組合關(guān)系來復(fù)用父加載器。當(dāng)一個(gè)ClassLoader收到來自類加載的請求,首先把該請求委派該父類ClassLoader處理,當(dāng)父類ClassLoader無法處理時(shí),才由當(dāng)前類ClassLoader來處理。對于每個(gè)ClassLoader這個(gè)方式,也就是父類的優(yōu)先于子類處理類加載的請求,那么也就是說任何一個(gè)請求第一次處理的便是最頂層的Bootstrap ClassLoader(啟動類加載器)。

        類加載器的層級查找順序依次為:啟動類加載器,擴(kuò)展類加載器,系統(tǒng)類加載器。系統(tǒng)類加載器是默認(rèn)的應(yīng)用程序類加載器。

        這樣的好處是不同層次的類加載器具有不同優(yōu)先級,比如所有Java對象的超級父類java.lang.Object,位于rt.jar,無論哪個(gè)類加載器加載該類,最終都是由啟動類加載器進(jìn)行加載,保證安全。即使用戶自己編寫一個(gè)java.lang.Object類并放入程序中,雖能正常編譯,但不會被加載運(yùn)行,保證不會出現(xiàn)混亂。那么有人會繼續(xù)追問,如果自己再自定義一個(gè)類加載器來加載自己定義的java.lang.Object類呢? 這樣做也是不會成功的,虛擬機(jī)將會拋出一異常。

         1protected?Class?loadClass(String?name,?boolean?resolve)
        2????throws?ClassNotFoundException
        3{
        4????synchronized?(getClassLoadingLock(name))?{
        5????????//檢查該類是否已經(jīng)加載過
        6????????Class?c?=?findLoadedClass(name);
        7????????if?(c?==?null)?{
        8????????????//如果該類沒有加載,則進(jìn)入該分支
        9????????????long?t0?=?System.nanoTime();
        10????????????try?{
        11????????????????if?(parent?!=?null)?{
        12????????????????????//當(dāng)父類的加載器不為空,則通過父類的loadClass來加載該類
        13????????????????????c?=?parent.loadClass(name,?false);
        14????????????????}?else?{
        15????????????????????//當(dāng)父類的加載器為空,則調(diào)用啟動類加載器來加載該類
        16????????????????????c?=?findBootstrapClassOrNull(name);
        17????????????????}
        18????????????}?catch?(ClassNotFoundException?e)?{
        19????????????????//非空父類的類加載器無法找到相應(yīng)的類,則拋出異常
        20????????????}
        21
        22????????????if?(c?==?null)?{
        23????????????????//當(dāng)父類加載器無法加載時(shí),則調(diào)用findClass方法來加載該類
        24????????????????long?t1?=?System.nanoTime();
        25????????????????c?=?findClass(name);?//用戶可通過覆寫該方法,來自定義類加載器
        26
        27????????????????//用于統(tǒng)計(jì)類加載器相關(guān)的信息
        28????????????????sun.misc.PerfCounter.getParentDelegationTime().addTime(t1?-?t0);
        29????????????????sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
        30????????????????sun.misc.PerfCounter.getFindClasses().increment();
        31????????????}
        32????????}
        33????????if?(resolve)?{
        34????????????//對類進(jìn)行l(wèi)ink操作
        35????????????resolveClass(c);
        36????????}
        37????????return?c;
        38????}
        39}

        當(dāng)開發(fā)者需要自定義類加載器時(shí),可通過覆寫loadClass()方法或者findClass()。

        三、自定義類加載器

        每一個(gè)ClassLoader都擁有自己獨(dú)立的類名稱空間,類是由ClassLoader將其加載到Java虛擬機(jī)中,故類是由加載它的ClassLoader和該類本身一起確定其在Java 運(yùn)行時(shí)環(huán)境的唯一性。故只有同一個(gè)ClassLoader加載的同一個(gè)類,才能算是Java 運(yùn)行時(shí)環(huán)境中的相同的兩個(gè)類。哪怕是來自同一個(gè)Class文件,即使被同一個(gè)虛擬機(jī)加載的兩個(gè)類,只要ClassLoader不同,那么也屬于不同的類。對于equals()、isinstanceof()等方法來判斷對象的相等或所屬關(guān)系都是需要基于同一個(gè)ClassLoader。

        自定義類加載器示例

         1package?com.yuanhh.classloader;
        2
        3import?java.io.IOException;
        4import?java.io.InputStream;
        5
        6public?class?ClassLoadDemo{
        7
        8????public?static?void?main(String[]?args)?throws?Exception?{
        9
        10????????ClassLoader?clazzLoader?=?new?ClassLoader()?{
        11????????????@Override
        12????????????public?Class?loadClass(String?name)?throws?ClassNotFoundException?{
        13????????????????try?{
        14????????????????????String?clazzName?=?name.substring(name.lastIndexOf(".")?+?1)?+?".class";
        15
        16????????????????????InputStream?is?=?getClass().getResourceAsStream(clazzName);
        17????????????????????if?(is?==?null)?{
        18????????????????????????return?super.loadClass(name);
        19????????????????????}
        20????????????????????byte[]?b?=?new?byte[is.available()];
        21????????????????????is.read(b);
        22????????????????????return?defineClass(name,?b,?0,?b.length);
        23????????????????}?catch?(IOException?e)?{
        24????????????????????throw?new?ClassNotFoundException(name);
        25????????????????}
        26????????????}
        27????????};
        28
        29????????String?currentClass?=?"com.yuanhh.classloader.ClassLoadDemo";
        30????????Class?clazz?=?clazzLoader.loadClass(currentClass);
        31????????Object?obj?=?clazz.newInstance();
        32
        33????????System.out.println(obj.getClass());
        34????????System.out.println(obj?instanceof?com.yuanhh.classloader.ClassLoadDemo);
        35????}
        36}

        上面代碼的輸出結(jié)果

        1class?com.yuanhh.classloader.ClassLoadDemo
        2false

        輸出結(jié)果的第一行,可以看出這個(gè)對象的確是com.yuanhh.classloader.ClassLoadDemo實(shí)例化的對象;但第二句是false,這是由于代碼中的obj是由用戶自定義的類加載器clazzLoader來加載的,可通過obj.getClass().getClassLoader()獲取該對象的類加載器為com.yuanhh.classloader.ClassLoadDemo$xxx,而虛擬機(jī)本身會由系統(tǒng)類加載器加載的類ClassLoadDemo,可通過ClassLoadDemo.class.getClassLoader()得其類加載器為sun.misc.Launcher$AppClassLoader@XXX。所以可得出結(jié)論:即使都是來自同一個(gè)Class文件,加載器不同,仍然是兩個(gè)不同的類,所以返回值是false。

        通過Class.forName()方法加載的類,采用的是系統(tǒng)類加載器。

        四、 經(jīng)典應(yīng)用場景

        • Tomcat,類加載器架構(gòu),自己定義了多個(gè)類加載器,

          • 保證了同一個(gè)服務(wù)器的兩個(gè)Web應(yīng)用程序的Java類庫隔離;

          • 保證了同一個(gè)服務(wù)器的兩個(gè)Web應(yīng)用程序的Java類庫又可以相互共享;比如多個(gè)Spring組織的應(yīng)用程序不能共享,會造成資源浪費(fèi);

          • 保證了服務(wù)器盡可能保證自身的安全不受不受部署Web應(yīng)用程序影響;

          • 支持JSP應(yīng)用的服務(wù)器,大多需要支持熱替換(HotSwap)功能。

        • OSGi(Open Service GateWay Initiative),是基于Java語言的動態(tài)模塊化規(guī)范。已成為Java世界的“事實(shí)上”的模塊化標(biāo)準(zhǔn),最為熟悉的案例的Eclipse IDE。

        source: //yuanfentiank789.github.io/2016/01/24/java-classloader

        喜歡,在看

        瀏覽 53
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評論
        圖片
        表情
        推薦
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            一级黄片免费观看 | 少妇小树林裸体野战视频在线观看 | 含羞草一区二区三区 | 摸了女同学的下面毛** | 亚洲一在线 | 放荡短裙少妇大叫受不了视频 | 青娱乐精品在线视频 | 中文字幕第32页 | 成年人免费视频在线 | 成人做爰黄AA片免费看三区动漫 |