<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          ClassLoader 類加載器模型

          共 6499字,需瀏覽 13分鐘

           ·

          2021-10-26 21:22

          一、 類加載器

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

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

          1.1 Bootstrap ClassLoader

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

          1.2 Extension ClassLoader

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

          1.3 Application ClassLoader

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

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

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

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

           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????????????//如果該類沒有加載,則進入該分支
          9????????????long?t0?=?System.nanoTime();
          10????????????try?{
          11????????????????if?(parent?!=?null)?{
          12????????????????????//當父類的加載器不為空,則通過父類的loadClass來加載該類
          13????????????????????c?=?parent.loadClass(name,?false);
          14????????????????}?else?{
          15????????????????????//當父類的加載器為空,則調用啟動類加載器來加載該類
          16????????????????????c?=?findBootstrapClassOrNull(name);
          17????????????????}
          18????????????}?catch?(ClassNotFoundException?e)?{
          19????????????????//非空父類的類加載器無法找到相應的類,則拋出異常
          20????????????}
          21
          22????????????if?(c?==?null)?{
          23????????????????//當父類加載器無法加載時,則調用findClass方法來加載該類
          24????????????????long?t1?=?System.nanoTime();
          25????????????????c?=?findClass(name);?//用戶可通過覆寫該方法,來自定義類加載器
          26
          27????????????????//用于統(tǒng)計類加載器相關的信息
          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????????????//對類進行l(wèi)ink操作
          35????????????resolveClass(c);
          36????????}
          37????????return?c;
          38????}
          39}

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

          三、自定義類加載器

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

          上面代碼的輸出結果

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

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

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

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

          • Tomcat,類加載器架構,自己定義了多個類加載器,

            • 保證了同一個服務器的兩個Web應用程序的Java類庫隔離;

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

            • 保證了服務器盡可能保證自身的安全不受不受部署Web應用程序影響;

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

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

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

          喜歡,在看

          瀏覽 53
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  息子无码一区二区三区免费 | 亚洲乱伦不卡 | 久久综合中文 | 韩国成人电影一区二区三区 | 亚洲毛片在线视频 |