中文字幕在线观看,亚洲а∨天堂久久精品9966,亚洲成a人片在线观看你懂的,亚洲av成人片无码网站,亚洲国产精品无码久久久五月天

談?wù)?Java 類加載機(jī)制

2018-11-22    來(lái)源:importnew

容器云強(qiáng)勢(shì)上線!快速搭建集群,上萬(wàn)Linux鏡像隨意使用

最近在學(xué)習(xí) Tomcat 架構(gòu),其中很重要的一個(gè)模塊是類加載器,因?yàn)橐郧皩W(xué)習(xí)的不夠深入,所以趁這個(gè)機(jī)會(huì)好好把類加載機(jī)制搞明白。

概述

類加載器主要分為兩類,一類是 JDK 默認(rèn)提供的,一類是用戶自定義的。 JDK 默認(rèn)提供三種類加載器:

  1. Bootstrap ClassLoader?啟動(dòng)類加載器:每次執(zhí)行?java?命令時(shí)都會(huì)使用該加載器為虛擬機(jī)加載核心類。該加載器是由?native code?實(shí)現(xiàn),而不是 Java 代碼,加載類的路徑為?<JAVA_HOME>/jre/lib。特別的?<JAVA_HOME>/jre/lib/rt.jar?中包含了?sun.misc.Launcher?類, 而?sun.misc.Launcher$ExtClassLoader?和?sun.misc.Launcher$AppClassLoader?都是?sun.misc.Launcher?的內(nèi)部類,所以拓展類加載器和系統(tǒng)類加載器都是由啟動(dòng)類加載器加載的。
  2. Extension ClassLoader, 拓展類加載器:用于加載拓展庫(kù)中的類。拓展庫(kù)路徑為?<JAVA_HOME>/jre/lib/ext/。實(shí)現(xiàn)類為?sun.misc.Launcher$ExtClassLoader
  3. System ClassLoader?系統(tǒng)類加載器:用于加載 CLASSPATH 中的類。實(shí)現(xiàn)類為?sun.misc.Launcher$AppClassLoader

用戶自定義的類加載器

  1. Custom ClassLoader, 一般都是?java.lang.ClassLoder?的子類

正統(tǒng)的類加載機(jī)制是基于雙親委派的,也就是當(dāng)調(diào)用類加載器加載類時(shí),首先將加載任務(wù)委派給雙親,若雙親無(wú)法加載成功時(shí),自己才進(jìn)行類加載。

在實(shí)例化一個(gè)新的類加載器時(shí),我們可以為其指定一個(gè)?parent,即雙親,若未顯式指定,則?System ClassLoader?就作為默認(rèn)雙親。

具體的說(shuō),類加載任務(wù)是由?ClassLoader?的?loadClass()?方法來(lái)執(zhí)行的,他會(huì)按照以下順序加載類:

  1. 通過(guò)?findLoadedClass()?看該類是否已經(jīng)被加載。該方法為 native code 實(shí)現(xiàn),若已加載則返回。
  2. 若未加載則委派給雙親,parent.loadClass(),若成功則返回。
  3. 若未成功,則調(diào)用?findClass()?方法加載類。java.lang.ClassLoader?中該方法只是簡(jiǎn)單的拋出一個(gè)?ClassNotFoundException?所以,自定義的 ClassLoader 都需要 Override?findClass()?方法。

類加載API

java.lang.ClassLoader

  • ClassLoader?是一個(gè)抽象類。
  • 待加載的類必須用?The Java? Language Specification?定義的全類名,全類名的定義請(qǐng)查閱?The Form of a Binary。
  • 給定一個(gè)全類名,類加載器應(yīng)該去定位該類所在的位置。通用的策略是將全類名轉(zhuǎn)換為類文件路徑,然后通過(guò)類文件路徑在文件系統(tǒng)中定位。
  • 每一個(gè)加載到內(nèi)存的類都由一個(gè) Class 對(duì)象來(lái)表示,每一個(gè) Class 對(duì)象都有一個(gè)指向加載該類的類加載器的引用。但是數(shù)組的 Class 對(duì)象是由 Java 運(yùn)行時(shí)環(huán)境創(chuàng)建的,通過(guò)?Class.getClassLoader()?方法返回的是數(shù)組元素的類加載器,若數(shù)組元素是基本類型,則返回?null,若類是由?Bootstrap ClassLoader?加載的話也是返回?null。
    public class Main {
        public static void main(String[] args) {
            // Object 類在 <java_home>/jre/lib/rt.jar 中,
            // 由 Bootstrap ClassLoader 加載,由于該類加載器是由 native code 編寫
            // 所以輸出為 null
            Object[] objects = new Object[5];
            System.out.println();
            System.out.println(objects.getClass().getClassLoader());
    
            // ZipFileAttributes 類在 <java_home>/jre/lib/ext/zipfs.jar 中,
            // 由 Extension ClassLoader 加載,
            // 輸出為  sun.misc.Launcher$ExtClassLoader@4b67cf4d
            ZipFileAttributes[] attributes = new ZipFileAttributes[5];
            System.out.println();
            System.out.println(attributes.getClass().getClassLoader());
    
            // Main 類是自定義的類,
            // 默認(rèn)由 System ClassLoader 加載,
            // 輸出為 sun.misc.Launcher$AppClassLoader@18b4aac2
            Main[] array = new Main[5];
            array[0] = new Main();
            System.out.println();
            System.out.println(array.getClass().getClassLoader());
        }
    }
  • ClassLoader?默認(rèn)支持并行加載,但是其子類必須調(diào)用?ClassLoader.registerAsParallelCapable()?來(lái)啟用并行加載
  • 一般來(lái)說(shuō),JVM 從本地文件系統(tǒng)加載類的行為是與平臺(tái)有關(guān)的。
  • defineClass()?方法可以將字節(jié)流轉(zhuǎn)換成一個(gè)?Class?對(duì)象。然后調(diào)用?Class.newInstance()?來(lái)創(chuàng)建類的實(shí)例

java.security.SecureClassLoader

增加了一層權(quán)限驗(yàn)證,因?yàn)殛P(guān)注點(diǎn)不在安全,所以暫不討論。

java.net.URLClassLoader

該類加載器用來(lái)加載 URL 指定的 JAR 文件或目錄中的類和資源,以?/?結(jié)尾的 URL 認(rèn)為是目錄,否則認(rèn)為是 JAR 文件。

// 嘗試通過(guò) URLClassLoader 來(lái)加載桌面下的 Test 類。
public class Main {
    public static void main(String[] args) {
        try {
            URL[] urls = new URL[1];
            URLStreamHandler streamHandler = null;
            File classPath = new File("/home/chen/Desktop/");
            String repository = (new URL("file", null,
                    classPath.getCanonicalPath() + File.separator))
                    .toString();
            urls[0] = new URL(null, repository, streamHandler);

            ClassLoader loader = new URLClassLoader(urls);

            Class testClass = loader.loadClass("Test");

            // output:  java.net.URLClassLoader@7f31245a
            System.out.println(testClass.getClassLoader());
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

Tomcat 8.5.15類加載機(jī)制

Tomcat 使用正統(tǒng)的類加載機(jī)制(雙親委派),但部分地方做了改動(dòng)。

  • Bootstrap classLoader?和?Extension classLoader?的作用不變。
  • System classLoader?正常情況下加載的是?CLASSPATH?下的類,但是 Tomcat 的啟動(dòng)腳本并未使用該變量,而是從以下倉(cāng)庫(kù)下加載類:
  1. $CATALINA_HOME/bin/bootstrap.jar?包含了 Tomcat 的啟動(dòng)類。在該啟動(dòng)類中創(chuàng)建了?Common classLoader、Catalina classLoadershared classLoader。因?yàn)?$CATALINA_BASE/conf/catalina.properties?中只對(duì)?common.loader?屬性做了定義,server.loader?和?shared.loader?屬性為空,所以默認(rèn)情況下,這三個(gè) classLoader 都是?CommonLoader。具體的代碼邏輯可以查閱?org.apache.catalina.startup.Bootstrap?類的?initClassLoaders()?方法和?createClassLoader()?方法。
  2. $CATALINA_BASE/bin/tomcat-juli.jar?包含了 Tomcat 日志模塊所需要的實(shí)現(xiàn)類。
  3. $CATALINA_HOME/bin/commons-daemon.jar。
  • Common classLoader?是位于 Tomcat 應(yīng)用服務(wù)器頂層的公用類加載器。由其加載的類可以由 Tomcat 自身類和所有應(yīng)用程序使用。掃描路徑由?$CATALINA_BASE/conf/catalina.properties?文件中的?common.loader?屬性定義。默認(rèn)是?$CATALINA_HOME/lib。
  • catalina classLoader?用于加載服務(wù)器內(nèi)部可見(jiàn)類,這些類應(yīng)用程序不能訪問(wèn)。
  • shared classLoader?用于加載應(yīng)用程序共享類,這些類服務(wù)器不會(huì)依賴。
  • Webapp classLoader?。每個(gè)應(yīng)用程序都會(huì)有一個(gè)獨(dú)一無(wú)二的?webapp classloader,他用來(lái)加載本應(yīng)用程序?/WEB-INF/classes?和?/WEB-INF/lib?下的類。

特別的:

Webapp classLoader?的默認(rèn)行為會(huì)與正常的雙親委派模式不同:

  1. 從?Bootstrap classloader?加載。
  2. 若沒(méi)有,從?/WEB-INF/classes?加載。
  3. 若沒(méi)有,從?/WEB-INF/lib/*.jar?加載。
  4. 若沒(méi)有,則依次從?System、Common、shared?加載(該步驟使用雙親委派)。

當(dāng)然了,我們也可以通過(guò)配置來(lái)使?Webapp classLoader?嚴(yán)格按照雙親委派模式加載類:

  1. 通過(guò)在工程的?META-INF/context.xml(和?WEB-INF/classes?在同一目錄下) 配置文件中添加?<Loader delegate="true"/>
  2. 因?yàn)?Webapp classLoader?的實(shí)現(xiàn)類是?org.apache.catalina.loader.WebappLoader,他有一個(gè)屬性叫?delegate, 用來(lái)控制類加載器的加載行為,默認(rèn)為?false,我們可以使用?set?方法,將其設(shè)為?true?來(lái)啟用嚴(yán)格雙親委派加載模式。

嚴(yán)格雙親委派模式加載步驟:

  1. 從?Bootstrap classloader?加載。
  2. 若沒(méi)有,則依次從?System、Common、shared?加載。
  3. 若沒(méi)有,從?/WEB-INF/classes?加載。
  4. 若沒(méi)有,從?/WEB-INF/lib/*.jar?加載。

參考資料

  1. The Java Class Loading Mechanism
  2. Java Classloader
  3. Class Loader HOW-TO – Apache Tomcat 8
  4. 《Tomcat 架構(gòu)解析》
  5. 《深入理解 Java 虛擬機(jī)》

標(biāo)簽: ssl 安全 代碼 服務(wù)器 腳本 權(quán)限 應(yīng)用服務(wù)器

版權(quán)申明:本站文章部分自網(wǎng)絡(luò),如有侵權(quán),請(qǐng)聯(lián)系:west999com@outlook.com
特別注意:本站所有轉(zhuǎn)載文章言論不代表本站觀點(diǎn)!
本站所提供的圖片等素材,版權(quán)歸原作者所有,如需使用,請(qǐng)與原作者聯(lián)系。

上一篇:Java反轉(zhuǎn)字符串的10種方法(代碼段)

下一篇:SpringBoot系列一:SpringBoot入門