成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_99国内精品久久久久久久

您的位置:首頁技術(shù)文章
文章詳情頁

一篇文章講透Tomcat的類加載機制

瀏覽:238日期:2023-03-19 16:51:41
目錄
  • - 前言 -
  • - JVM 類加載器 -
    • 1、JVM類加載器
    • 2、類加載器的源碼
  • - Tomcat 的類加載機制 -
    • 1、加載機制的特點
    • 2、Tomcat 的類加載方案
    • 3、分析應用類加載器的加載過程
  • 總結(jié)

    - 前言 -

    你了解 Apache Tomcat 的類加載機制嗎?本文將從底層原理切入,徹底揭秘 Tomcat 類加載所涉及的源碼、機制和方案,助你深入掌握 Tomcat 類加載核心!

    - JVM 類加載器 -

    1、JVM類加載器

    說起 Tomcat 類加載器,就不得不先簡單說一下 JVM 類加載器,如下圖所示:

    • 啟動類加載器:Bootstrap ClassLoader,用于加載JVM提供的基礎(chǔ)運行類,即位于%JAVA_HOME%/jre/lib目錄下的核 心類庫;
    • 擴展類加載器:Extension ClassLoader, Java提供的一個標準的擴展機制用于加載除核心類庫外的Jar包,即只要復制 到指定的擴展目錄(可以多個)下的Jar, JVM會自動加載(不需要通過-classpath指定)。默認的擴展目錄是%JAVA_HOME%加e/lib/ext。典型的應用場景就是,Java使用該類加載 器加載JVM默認提供的但是不屬于核心類庫的Jar。不推薦將應用程序依賴的 類庫放置到擴展目錄下,因為該目錄下的類庫對所有基于該JVM運行的應用程序可見;
    • 應用程序類加載器:Application ClassLoader ,用于加載環(huán)境變量CLASSPATH (不推薦使用)指定目錄下的或者-classpath運行 參數(shù)指定的Jar包。System類加載器通常用于加載應用程序Jar包及其啟動入口類(Tomcat 的Bootstrap類即由System類加載器加載)。

    這些類加載器的工作原理是一樣的,區(qū)別是它們的加載路徑不同,也就是說 findClass 這個方法查找的路徑不同。

    雙親委托機制是為了保證一個 Java 類在 JVM 中是唯一的,假如你不小心寫了一個與 JRE 核心類同名的類,比如 Object 類,雙親委托機制能保證加載的是 JRE 里的那個 Object 類,而不是你寫的 Object 類。

    這是因為 AppClassLoader 在加載你的 Object 類時,會委托給 ExtClassLoader 去加載,而 ExtClassLoader 又會委托給 BootstrapClassLoader,BootstrapClassLoader 發(fā)現(xiàn)自己已經(jīng)加載過了 Object 類,會直接返回,不會去加載你寫的 Object 類。

    這里請注意,類加載器的父子關(guān)系不是通過繼承來實現(xiàn)的,比如 AppClassLoader 并不是 ExtClassLoader 的子類,而是說 AppClassLoader 的 parent 成員變量指向 ExtClassLoader 對象。同樣的道理,如果你要自定義類加載器,不去繼承 AppClassLoader,而是繼承 ClassLoader 抽象類,再重寫 findClass 和 loadClass 方法即可,Tomcat 就是通過自定義類加載器來實現(xiàn)自己的類加載邏輯。不知道你發(fā)現(xiàn)沒有,如果你要打破雙親委托機制,就需要重寫 loadClass 方法,因為 loadClass 的默認實現(xiàn)就是雙親委托機制。

    2、類加載器的源碼

    public abstract class ClassLoader {  //  每個類加載器都有一個父加載器  private final ClassLoader parent;  public Class<?> loadClass(String name) throws ClassNotFoundException {return loadClass(name, false);    }     protected Class<?> loadClass(String name, boolean resolve)throws ClassNotFoundException    {    // First, check if the class has already been loaded    Class<?> c = findLoadedClass(name);   // 如果沒有加載過    if (c == null) {if (parent != null) {  //  先委托給父加載器去加載,注意這是個遞歸調(diào)用 c = parent.loadClass(name, false);} else { // 如果父加載器為空,查找 Bootstrap 加載器是不是加載過了   c = findBootstrapClassOrNull(name);}          // 如果父加載器沒加載成功,調(diào)用自己的 findClass 去加載if (c == null) {    c = findClass(name);}    }     return c;}    }    //ClassLoader 中findClass方式需要被子類覆蓋,下面這段代碼就是對應代碼      protected Class<?> findClass(String name){       //1. 根據(jù)傳入的類名 name,到在特定目錄下去尋找類文件,把.class 文件讀入內(nèi)存  ...       //2. 調(diào)用 defineClass 將字節(jié)數(shù)組轉(zhuǎn)成 Class 對象       return defineClass(buf, off, len);    }      // 將字節(jié)碼數(shù)組解析成一個 Class 對象,用 native 方法實現(xiàn)    protected final Class<?> defineClass(byte[] b, int off, int len){        }    }

    我們自定義類加載器就需要重寫ClassLoader的loadClass方法。

    - Tomcat 的類加載機制 -

    1、加載機制的特點

    隔離性:Web應用類庫相互隔離,避免依賴庫或者應用包相互影響。設想一下,如果我們 有兩個Web應用,一個釆用了Spring 2.5, 一個采用了Spring 4.0,而應用服務器使用一個 類加載器加載,那么Web應用將會由于Jar包覆蓋而導致無法啟動成功;

    靈活性:既然Web應用之間的類加載器相互獨立,那么我們就能只針對一個Web應用進行 重新部署,此時該Web應用的類加載器將會重新創(chuàng)建,而且不會影響其他Web應用。如果 釆用一個類加載器,顯然無法實現(xiàn),因為只有一個類加載器的時候,類之間的依賴是雜 亂無章的,無法完整地移除某個Web應用的類;

    性能:由于每個Web應用都有一個類加載器,因此Web應用在加載類時,不會搜索其他 Web應用包含的Jar包,性能自然高于應用服務器只有一個類加載器的情況。

    2、Tomcat 的類加載方案

    • 引導類加載器 和 擴展類加載器 的作⽤不變;
    • 系統(tǒng)類加載器正常情況下加載的是 CLASSPATH 下的類,但是 Tomcat 的啟動腳本并未使⽤該變量,⽽是加載tomcat啟動的類,⽐如bootstrap.jar,通常在catalina.bat或者catalina.sh中指定。位于CATALINA_HOME/bin下;
    • Common 通⽤類加載器加載Tomcat使⽤以及應⽤通⽤的⼀些類,位于CATALINA_HOME/lib下,⽐如servlet-api.jar;
    • Catalina ClassLoader ⽤于加載服務器內(nèi)部可⻅類,這些類應⽤程序不能訪問;
    • SharedClassLoader ⽤于加載應⽤程序共享類,這些類服務器不會依賴;
    • WebappClassLoader,每個應⽤程序都會有⼀個獨⼀⽆⼆的Webapp ClassLoader,他⽤來加載本應⽤程序 /WEB-INF/classes 和 /WEB-INF/lib 下的類。

    tomcat 8.5 默認改變了嚴格的雙親委派機制:

    • 從緩存中加載;
    • 如果緩存中沒有,會先調(diào)用ExtClassLoader進行加載, 擴展類加載器是遵循雙親委派的,他會調(diào)用bootstrap,查看對應的lib有沒有,然后回退給ExtClassLoader對擴展包下的數(shù)據(jù)進行加載;
    • 如果未加載到,則從 /WEB-INF/classes加載;
    • 如果未加載到,則從 /WEB-INF/lib/*.jar 加載如果未加載到,WebAppclassLoader 會委派給SharedClassLoader,SharedClassLoad會委派給CommonClassLoader.....,依次委派給BootstrapClassLoader, 然后BootstrapClassLoader 在自己目錄中查找對應的類如果有則進行加載,如果沒有他會委派給下一級ExtClassLoader,ExtClassLoader再查找自己目錄下的類,如果有則加載如果沒有則委派給下一級……遵循雙親委派原則。

    3、分析應用類加載器的加載過程

    應用類加載器為WebappClassLoader ,他的loadClass在他的父類WebappClassLoaderBase中。

      public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {synchronized (getClassLoadingLock(name)) {    if (log.isDebugEnabled())log.debug("loadClass(" + name + ", " + resolve + ")");    Class<?> clazz = null;    // Log access to stopped class loader    checkStateForClassLoading(name);        //從當前ClassLoader的本地緩存中加載類,如果找到則返回    clazz = findLoadedClass0(name);    if (clazz != null) {if (log.isDebugEnabled())    log.debug("  Returning class from cache");if (resolve)    resolveClass(clazz);return clazz;    }    // 本地緩存沒有的情況下,調(diào)用ClassLoader的findLoadedClass方法查看jvm是否已經(jīng)加載過此類,如果已經(jīng)加載則直接返回。    clazz = findLoadedClass(name);    if (clazz != null) {if (log.isDebugEnabled())    log.debug("  Returning class from cache");if (resolve)    resolveClass(clazz);return clazz;    }    String resourceName = binaryNameToPath(name, false);    //此時的javaseClassLoader是擴展類加載器  是把擴展類加載器賦值給了javaseClassLoader    ClassLoader javaseLoader = getJavaseClassLoader();    boolean tryLoadingFromJavaseLoader;    try {      .....    //如果可以用getResource得到    //如果能用擴展類加載器的getResource得到就證明可以被擴展類加載器加載到接下來安排擴展類加載器加載    if (tryLoadingFromJavaseLoader) {try {    //使用擴展類加載器進行加載    clazz = javaseLoader.loadClass(name);    if (clazz != null) {if (resolve)    resolveClass(clazz);return clazz;    }} catch (ClassNotFoundException e) {    // Ignore}    }    // (0.5) Permission to access this class when using a SecurityManager    if (securityManager != null) {int i = name.lastIndexOf(".");if (i >= 0) {    try {securityManager.checkPackageAccess(name.substring(0,i));    } catch (SecurityException se) {String error = "Security Violation, attempt to use " +    "Restricted Class: " + name;log.info(error, se);throw new ClassNotFoundException(error, se);    }}    }    boolean delegateLoad = delegate || filter(name, true);    // (1) Delegate to our parent if requested    //如果是true就是用父類加載器進行加載    if (delegateLoad) {if (log.isDebugEnabled())    log.debug("  Delegating to parent classloader1 " + parent);try {    clazz = Class.forName(name, false, parent);    if (clazz != null) {if (log.isDebugEnabled())    log.debug("  Loading class from parent");if (resolve)    resolveClass(clazz);return clazz;    }} catch (ClassNotFoundException e) {    // Ignore}    }    // (2) Search local repositories    if (log.isDebugEnabled())log.debug("  Searching local repositories");    try {// 本地進行加載clazz = findClass(name);if (clazz != null) {    if (log.isDebugEnabled())log.debug("  Loading class from local repository");    if (resolve)resolveClass(clazz);    return clazz;}    } catch (ClassNotFoundException e) {// Ignore    }    // (3) Delegate to parent unconditionally    //到這里還是沒有加載上再次嘗試使用父類加載器進行加載    if (!delegateLoad) {    if (log.isDebugEnabled())    log.debug("  Delegating to parent classloader at end: " + parent);try {    clazz = Class.forName(name, false, parent);    if (clazz != null) {if (log.isDebugEnabled())    log.debug("  Loading class from parent");if (resolve)    resolveClass(clazz);return clazz;    }} catch (ClassNotFoundException e) {    // Ignore}    }}throw new ClassNotFoundException(name);    }

    注:在37行英文注釋中標注獲取的是系統(tǒng)類加載器,但我們debug的時候會發(fā)現(xiàn)他是擴展類加載器,實際中我們可以推斷出他應該是擴展類加載器,因為如果我們加載的類在擴展類加載器路徑下已經(jīng)存在的話,那我們直接調(diào)用系統(tǒng)類加載器是就是錯誤的了,下圖為debug后獲取的類加載器的驗證。

    總結(jié)

    tomcat打破了雙親委派的原則,實際是在應用類加載器中打破了雙親委派,其他類加載器還是遵循雙親委派的。

    到此這篇關(guān)于Tomcat類加載機制的文章就介紹到這了,更多相關(guān)Tomcat類加載機制內(nèi)容請搜索以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持!

    標簽: Tomcat
    成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_99国内精品久久久久久久
    成人ar影院免费观看视频| 久久综合精品国产一区二区三区 | 欧美1区免费| 日韩精品中文字幕在线一区| 国内不卡的二区三区中文字幕| 在线视频国产一区| 天堂va蜜桃一区二区三区| 久久国产日韩| 日本午夜一本久久久综合| 91国偷自产一区二区三区成为亚洲经典| 偷窥国产亚洲免费视频| 国产精品婷婷| 亚洲综合一区二区三区| 国产精品一区免费观看| 五月天久久比比资源色| 色婷婷综合久久久中文一区二区| 性做久久久久久久久| 久久婷婷丁香| 免费在线观看一区| 欧美午夜一区二区三区免费大片| 日本亚洲视频在线| 欧美日韩国产高清一区二区| 国模大尺度一区二区三区| 日韩一级免费一区| av午夜一区麻豆| 欧美国产成人在线| 亚洲经典自拍| 亚洲成人tv网| 欧美三级在线播放| 国产福利精品一区二区| 26uuu另类欧美| 欧美喷水视频| 亚洲另类在线一区| 噜噜噜躁狠狠躁狠狠精品视频| 天天色 色综合| 欧美怡红院视频| 国产福利一区二区三区视频 | 3atv一区二区三区| 成人av资源下载| 国产性做久久久久久| 狠狠噜噜久久| 日日夜夜免费精品视频| 欧美日韩mp4| 99精品热视频| 亚洲精品成人少妇| 欧美四级电影网| 99久久777色| 一区二区理论电影在线观看| 欧洲色大大久久| eeuss国产一区二区三区| 亚洲欧洲av一区二区三区久久| 在线亚洲伦理| 理论电影国产精品| 国产天堂亚洲国产碰碰| 日韩视频一区二区三区在线播放免费观看| 亚洲18女电影在线观看| 欧美一级艳片视频免费观看| 欧美日韩精品免费观看视一区二区| 亚洲伊人色欲综合网| 欧美日韩精品一区二区| 欧美1区免费| 午夜精品久久久久久久| 日韩一区二区在线免费观看| 黄色成人av网站| 麻豆一区二区三区| 精品理论电影在线| 一区二区国产日产| 国产一区二区美女诱惑| 国产欧美日韩在线观看| 一区二区三区成人| 91福利在线播放| 99vv1com这只有精品| 夜夜亚洲天天久久| 7777精品伊人久久久大香线蕉的 | 欧洲人成人精品| 99re这里都是精品| 香蕉久久一区二区不卡无毒影院 | 欧美日韩久久不卡| 欧美日本在线| 青青国产91久久久久久| 精品久久久久久最新网址| 99视频精品免费观看| 狠狠色综合日日| 中文字幕亚洲一区二区av在线| 色丁香久综合在线久综合在线观看| www.亚洲精品| 亚洲成a人片在线观看中文| 精品国产一区a| 欧美专区一区二区三区| 成人免费视频视频在线观看免费| 国产精品电影一区二区三区| 在线观看免费成人| 欧美日韩一区在线播放| 美女一区二区久久| 国产精品理伦片| 欧美日韩高清一区| 国产精品一区二区三区免费观看 | 你懂的网址国产 欧美| 日韩va欧美va亚洲va久久| www国产亚洲精品久久麻豆| 蜜桃久久av| 欧美三级小说| 国产精品88av| 亚洲国产精品天堂| 中文在线免费一区三区高中清不卡| 欧美三区免费完整视频在线观看| 亚洲高清在线| aaa亚洲精品一二三区| 日韩电影免费在线观看网站| 久久久高清一区二区三区| 在线视频观看一区| 亚洲欧洲日夜超级视频| 波多野结衣91| 美女www一区二区| 一区二区三区日韩欧美| 精品久久久久99| 色婷婷国产精品综合在线观看| 欧美久久综合| 国产精品一级二级三级| 亚洲午夜久久久| 国产日产欧美精品一区二区三区| 欧美三级电影在线观看| 国产精品美女诱惑| 午夜国产精品视频| 国产成+人+日韩+欧美+亚洲| 天堂成人国产精品一区| 亚洲欧美色图小说| 国产农村妇女毛片精品久久麻豆| 欧美精选午夜久久久乱码6080| 亚洲一区二区三区午夜| 国模一区二区三区| 99国内精品久久| 国产一区二区三区免费在线观看| 亚洲福利一区二区| 自拍视频在线观看一区二区| 久久影院午夜论| 91精品国产综合久久精品图片| 久久综合久久综合这里只有精品| 亚洲欧洲日夜超级视频| 午夜欧美精品久久久久久久| 成人午夜私人影院| 久久国产欧美日韩精品| 天堂av在线一区| 亚洲成a人v欧美综合天堂| 一区二区三区在线免费播放| 国产精品久久久久婷婷二区次| 久久久亚洲午夜电影| 日韩精品专区在线影院观看| 欧美日韩成人一区| 日本大香伊一区二区三区| 亚洲尤物影院| 性欧美长视频| 国产亚洲一区在线播放| 亚洲激情亚洲| 91久久国产自产拍夜夜嗨| 欧美日韩久久| 欧美成人日本| 97久久久精品综合88久久| 不卡一区二区中文字幕| 成人亚洲一区二区一| 国产高清在线精品| 懂色av噜噜一区二区三区av| 国产不卡视频在线播放| 国产精品白丝av| 国产成人精品免费在线| 粉嫩av一区二区三区| 国产成人高清视频| 国产91清纯白嫩初高中在线观看| 国产白丝精品91爽爽久久| 风流少妇一区二区| 北岛玲一区二区三区四区| av一区二区三区黑人| 97久久超碰精品国产| 91在线丨porny丨国产| 91免费视频大全| 午夜欧美视频| 国模精品一区二区三区| 亚洲人成免费| 亚洲一区二区三区午夜| 久久精品毛片| 在线亚洲人成电影网站色www| 欧洲亚洲国产日韩| 欧美日本在线观看| 欧美一级高清片| 日韩精品一区二区三区swag| 精品日韩99亚洲| 国产亚洲欧美日韩俺去了| 国产欧美一区二区精品久导航| 国产网站一区二区| 亚洲女同ⅹxx女同tv| 亚洲一区二区三区四区在线观看 | 精品一区精品二区高清| 国产麻豆视频一区二区| 成人免费毛片片v| 欧美一区高清| 在线精品在线| 久久久99国产精品免费| 欧美在线看片a免费观看| 在线播放中文一区| 精品国产免费久久|