<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    關于ClassLoader In Tomcat 的研究

    Posted on 2007-05-04 09:22 久城 閱讀(4139) 評論(7)  編輯  收藏 所屬分類: Java轉載

    收回五一假期那顆破碎的心,繼續我的程序人生。

    今天打算研究下ClassLoader在Tomcat中的工作。

    以下文字來自http://hi.baidu.com/wuzejian/blog/item/678c21e92aa6483eb90e2d21.html

    1 - Tomcat的類載入器的結構

    Tomcat Server在啟動的時候將構造一個ClassLoader樹,以保證模塊的類庫是私有的
    Tomcat Server的ClassLoader結構如下:
    其中:
    - Bootstrap - 載入JVM自帶的類和$JAVA_HOME/jre/lib/ext/*.jar
    - System - 載入$CLASSPATH/*.class
    - Common - 載入$CATALINA_HOME/common/...,它們對TOMCAT和所有的WEB APP都可見
    - Catalina - 載入$CATALINA_HOME/server/...,它們僅對TOMCAT可見,對所有的WEB APP都不可見
    - Shared - 載入$CATALINA_HOME/shared/...,它們僅對所有WEB APP可見,對TOMCAT不可見(也不必見)
    - WebApp? - 載入ContextBase?/WEB-INF/...,它們僅對該WEB APP可見

     

    2 - ClassLoader的工作原理

    每個運行中的線程都有一個成員contextClassLoader,用來在運行時動態地載入其它類
    系統默認的contextClassLoader是systemClassLoader,所以一般而言java程序在執行時可以使用JVM自帶的類、$JAVA_HOME/jre/lib/ext/中的類和$CLASSPATH/中的類
    可以使用Thread.currentThread().setContextClassLoader(...);更改當前線程的contextClassLoader,來改變其載入類的行為

    ClassLoader被組織成樹形,一般的工作原理是:
    1) 線程需要用到某個類,于是contextClassLoader被請求來載入該類
    2) contextClassLoader請求它的父ClassLoader來完成該載入請求
    3) 如果父ClassLoader無法載入類,則contextClassLoader試圖自己來載入

    注意:WebApp?ClassLoader的工作原理和上述有少許不同:
    它先試圖自己載入類(在ContextBase?/WEB-INF/...中載入類),如果無法載入,再請求父ClassLoader完成

    由此可得:
    - 對于WEB APP線程,它的contextClassLoader是WebApp?ClassLoader
    - 對于Tomcat Server線程,它的contextClassLoader是CatalinaClassLoader

    3 - 部分原代碼分析

    3.1 - org/apache/catalina/startup/Bootstrap.java

    Tomcat Server線程的起點
    構造ClassLoader樹,并設置Tomcat Server線程的contextClassLoader為catalinaloader
    載入若干類,然后轉入org.apache.catalina.startup.Catalina類中

    ---------------------------------------
    package org.apache.catalina.startup;

    // JDK類庫

    import java.io.File;
    import java.io.IOException;
    import java.lang.reflect.Method;
    import java.net.MalformedURLException;
    import java.net.URL;
    import java.util.ArrayList;

    // apache自己的類庫

    import org.apache.catalina.loader.Extension;
    import org.apache.catalina.loader.StandardClassLoader;

    /**
     * Boostrap loader for Catalina.     This application constructs a class loader
     * for use in loading the Catalina internal classes (by accumulating all of the
     * JAR files found in the "server" directory under "catalina.home"), and
     * starts the regular execution of the container.     The purpose of this
     * roundabout approach is to keep the Catalina internal classes (and any
     * other classes they depend on, such as an XML parser) out of the system
     * class path and therefore not visible to application level classes.
     *
     * 
    @author Craig R. McClanahan
     * 
    @version $Revision: 1.36 $ $Date: 2002/04/01 19:51:31 $
     
    */


    /**
     * 該類的main方法的主要任務: --------------------------
     * 
     * 1,創建TOMCAT自己的類載入器(ClassLoader) +---------------------------+ | Bootstrap | | | | |
     * System | | | | | Common | | / \ | | Catalina Shared |
     * +---------------------------+ 其中: - Bootstrap -
     * 載入JVM自帶的類和$JAVA_HOME/jre/lib/ext/*.jar - System - 載入$CLASSPATH/*.class -
     * Common - 載入$CATALINA_HOME/common/,它們對TOMCAT和所有的WEB APP都可見 - Catalina -
     * 載入$CATALINA_HOME/server/,它們僅對TOMCAT可見,對所有的WEB APP都不可見 - Shared -
     * 載入$CATALINA_HOME/shared/,它們僅對所有WEB APP可見,對TOMCAT不可見(也不必見)
     * 注意:當一個ClassLoader被請求載入一個類時,它首先請求其父ClassLoader完成載入,
     * 僅當其父ClassLoader無法載入該類時,才試圖自己載入該類 2,改變本身線程的默認ClassLoader(本線程就是Tomcat
     * Server線程,類載入器是catalinaLoader)
     * 3,讓catalinaLoader載入一些類,類的位置在$CATALINA_HOME/server/lib/catalina.jar中
     * 4,創建org.apache.catalina.startup.Catalina類的一個實例startupInstance,并為其調用方法:
     * startupInstance.setParentClassLoader(sharedLoader);
     * startupInstance.process(args);
     * 
     * 
     * 有關ClassLoader的說明: -----------------------
     * 
     * 每個被DEPLOY的WEB APP都會被創建一個ClassLoader,用來載入該WEB APP自己的類
     * 這些類的位置是webappX/WEB-INF/classes/*.class和webappX/WEB-INF/lib/*.jar
     * 
     * ClassLoader的工作流程是: 1) 收到一個載入類的的請求 2) 請求其父ClassLoader來完成該類的載入 3)
     * 如果父ClassLoader無法載入,則自己試圖完成該類的載入
     * 
     * 特別注意WEB APP自己的ClassLoader的實現與眾不同: 它先試圖從WEB APP自己的目錄里載入,如果失敗則請求父ClassLoader的代理
     * 這樣可以讓不同的WEB APP之間的類載入互不干擾
     * 
     * WEB APP的ClassLoader的層次結構是: +----------------------------+ | Shared | | / \
     *  | | Webapp1 Webapp2  | +----------------------------+ 故對于一個WEB
     * APP,其類載入的優先順序如下: - /WEB-INF/classes/*.class 和 /WEB-INF/lib/*.jar - Bootstrap
     * classes of JVM - System class loader classes - $CATALINA_HOME/common/ -
     * $CATALINA_HOME/shared/
     * 
     * 
     * 小結: ------
     * 
     * 綜上分析 - Tomcat Server線程使用的classLoader是Catalina - 每個WEB
     * APP線程使用的classloader是Webapp?
     * 
     
    */


    public final class Bootstrap {

        
    /**
         * DEBUG級別
         
    */


        
    private static int debug = 0;

        
    /**
         * 腳本執行該程序時,提供以下的系統屬性: java.endorsed.dirs="$JAVA_ENDORSED_DIRS" -classpath
         * "$CLASSPATH" \ java.security.manager \
         * java.security.policy=="$CATALINA_BASE"/conf/catalina.policy \
         * catalina.base="$CATALINA_BASE" \ catalina.home="$CATALINA_HOME" \
         * java.io.tmpdir="$CATALINA_TMPDIR" \
         * 
         * 
    @param args
         *            Command line arguments to be processed
         
    */


        
    public static void main(String args[]) {

            
    // 設置debug

            
    for (int i = 0; i < args.length; i++{
                
    if ("-debug".equals(args[i]))
                    debug 
    = 1;
            }


            
    // 設置好系統屬性catalina.base,即保證其有值

            
    if (System.getProperty("catalina.base"== null)
                System.setProperty(
    "catalina.base", getCatalinaHome());

            
    // 創建三個ClassLoader
            
    // 這三個對象是通過ClassLoaderFactory的靜態方法創建的
            
    // 其實際類型是StandardClassLoader,完成tomcat自定義的類載入
            
    // 這些類對非tomcat及其上的webapp的其它java程序不可見,故用自己的Classloader載入

            ClassLoader commonLoader 
    = null;
            ClassLoader catalinaLoader 
    = null;
            ClassLoader sharedLoader 
    = null;
            
    try {

                File unpacked[] 
    = new File[1];
                File packed[] 
    = new File[1];
                File packed2[] 
    = new File[2];

                ClassLoaderFactory.setDebug(debug);

                
    // $CATALINA_HOME/common/classes/*.class - 未壓縮的類
                
    // $CATALINA_HOME/common/endorsed/*.jar - 壓縮的類(endorse:支持)
                
    // $CATALINA_HOME/common/lib/*.jar - 壓縮的類
                
    // 這些類是被tomcat server以及所有的webapp所共享的類,由commonLoader負責載入

                unpacked[
    0= new File(getCatalinaHome(), "common" + File.separator
                        
    + "classes");
                packed2[
    0= new File(getCatalinaHome(), "common" + File.separator
                        
    + "endorsed");
                packed2[
    1= new File(getCatalinaHome(), "common" + File.separator
                        
    + "lib");
                commonLoader 
    = ClassLoaderFactory.createClassLoader(unpacked,
                        packed2, 
    null);

                
    // $CATALINA_HOME/server/classes/*.class
                
    // $CATALINA_HOME/server/lib/*.jar
                
    // 這些類是僅被tomcat server使用而對webapp不可見的類,由catalinaLoader負責載入

                unpacked[
    0= new File(getCatalinaHome(), "server" + File.separator
                        
    + "classes");
                packed[
    0= new File(getCatalinaHome(), "server" + File.separator
                        
    + "lib");
                catalinaLoader 
    = ClassLoaderFactory.createClassLoader(unpacked,
                        packed, commonLoader);

                
    // $CATALINA_BASE/shared/classes/*.class
                
    // $CATALINA_BASE/shared/lib/*.jar
                
    // 這些類是僅被tomcat的webapp使用的類,由sharedLoader負責載入

                unpacked[
    0= new File(getCatalinaBase(), "shared" + File.separator
                        
    + "classes");
                packed[
    0= new File(getCatalinaBase(), "shared" + File.separator
                        
    + "lib");
                sharedLoader 
    = ClassLoaderFactory.createClassLoader(unpacked,
                        packed, commonLoader);

                
    // 注意三個自己定置的ClassLoader的層次關系:
                
    // systemClassLoader (root)
                
    // +--- commonLoader
                
    // +--- catalinaLoader
                
    // +--- sharedLoader

            }
     catch (Throwable t) {
                log(
    "Class loader creation threw exception", t);
                System.exit(
    1);

            }


            
    // 為當前的線程更改其contextClassLoader
            
    // 一般的線程默認的contextClassLoader是系統的ClassLoader(所有其它自定義ClassLoader的父親)
            
    // 當該線程需要載入類時,將使用自己的contextClassLoader來尋找并載入類
            
    // 更改contextClassLoader可以更改該線程的尋找和載入類的行為,但不影響到其它線程
            
    // 注意!Tomcat Server線程使用的是catalinaLoader

            Thread.currentThread().setContextClassLoader(catalinaLoader);

            
    // Load our startup class and call its process() method

            
    try {

                
    // 預載入catalinalLoader的一些類

                SecurityClassLoad.securityClassLoad(catalinaLoader);

                
    // 獲得tomcat的啟動類:org.apache.catalina.startup.Catalina,并創建該類的一個實例

                
    if (debug >= 1)
                    log(
    "Loading startup class");
                Class startupClass 
    = catalinaLoader
                        .loadClass(
    "org.apache.catalina.startup.Catalina");
                Object startupInstance 
    = startupClass.newInstance();

                
    // 設置startupInstance的父ClassLoader,相當于執行:
                
    // Catalina startupInstance = new Catailina();
                
    // startupInstance.setParentClassLoader(sharedLoader);
                
    // 詳情參考類org.apache.catalina.startup.Catalina

                
    if (debug >= 1)
                    log(
    "Setting startup class properties");
                String methodName 
    = "setParentClassLoader";
                Class paramTypes[] 
    = new Class[1];
                paramTypes[
    0= Class.forName("java.lang.ClassLoader");
                Object paramValues[] 
    = new Object[1];
                paramValues[
    0= sharedLoader;
                Method method 
    = startupInstance.getClass().getMethod(methodName,
                        paramTypes);
                method.invoke(startupInstance, paramValues);

                
    // 使用main方法獲得的參數args來執行process方法,相當于:
                
    // startupInstance.process(args);
                
    // 詳情參考類org.apache.catalina.startup.Catalina

                
    if (debug >= 1)
                    log(
    "Calling startup class process() method");
                methodName 
    = "process";
                paramTypes 
    = new Class[1];
                paramTypes[
    0= args.getClass();
                paramValues 
    = new Object[1];
                paramValues[
    0= args;
                method 
    = startupInstance.getClass().getMethod(methodName,
                        paramTypes);
                method.invoke(startupInstance, paramValues);

            }
     catch (Exception e) {
                System.out.println(
    "Exception during startup processing");
                e.printStackTrace(System.out);
                System.exit(
    2);
            }


        }


        
    /**
         * 返回$CATALINA_HOME變量。如果該變量沒有定義,則將之賦值為用戶的當前工作目錄。
         
    */


        
    private static String getCatalinaHome() {
            
    return System.getProperty("catalina.home", System
                    .getProperty(
    "user.dir"));
        }


        
    /**
         * 返回$CATALINA_BASE變量。如果該變量沒有定義,則將之賦值為$CATALINA_HOME。
         
    */


        
    private static String getCatalinaBase() {
            
    return System.getProperty("catalina.base", getCatalinaHome());
        }


        
    /**
         * 輸出LOG信息。
         
    */


        
    private static void log(String message) {

            System.out.print(
    "Bootstrap: ");
            System.out.println(message);

        }


        
    /**
         * 輸出由異常引起的LOG信息。
         
    */


        
    private static void log(String message, Throwable exception) {

            log(message);
            exception.printStackTrace(System.out);

        }


    }
    --------------------------------------------------------
               +-----------------------------+
               |            Bootstrap              |
               |                |                  |
               |             System                |
               |                |                  |
               |             Common                |
               |            /         \               |
               |        Catalina     Shared           |
               |                  /       \           |
               |             WebApp1     WebApp2      |
               +-----------------------------+
    還有很多讓我疑惑的地方,轉過來慢慢學習。
    


    歡迎來訪!^.^!
    本BLOG僅用于個人學習交流!
    目的在于記錄個人成長.
    所有文字均屬于個人理解.
    如有錯誤,望多多指教!不勝感激!

    Feedback

    # re: 關于ClassLoader In Tomcat 的研究[未登錄]  回復  更多評論   

    2007-05-04 10:38 by Test
    testtest

    # re: 關于ClassLoader In Tomcat 的研究  回復  更多評論   

    2007-05-04 10:56 by BeanSoft
    哥們可以研究研究熱加載, 很有意思的哦... 不用重啟可以更新類庫

    # re: 關于ClassLoader In Tomcat 的研究  回復  更多評論   

    2007-05-04 11:04 by 久城
    @BeanSoft
    樓上乃高人也。我的導師也提過這個內容。很想研究研究。在tomcat中經常遇到這樣的問題,必須要重新啟動Tomcat才能加載自己已更新的類。我想,剖析一下Tomcat中的ClassLoader,應該能解決這個問題。正好寫在畢業論文里。只是現在可以參考的資料好少..還在探索中..

    # re: 關于ClassLoader In Tomcat 的研究  回復  更多評論   

    2007-05-04 13:05 by BeanSoft
    高人不敢當了. 原來看過一些, 但是感覺熱加載還是挺復雜的. 可以參考 Tomcat 里面有 Reload 字樣的文集, JBoss 的熱加載據說做的比較好. 原來試過, 但是才疏學淺, 遇到些問題.

    org\jboss\mx\loading 這個包下面的是類加載

    Tomcat 5.0 的位于:
    org\apache\catalina\loader

    # re: 關于ClassLoader In Tomcat 的研究  回復  更多評論   

    2007-05-04 13:23 by 久城
    very thanks!

    # re: 關于ClassLoader In Tomcat 的研究[未登錄]  回復  更多評論   

    2008-04-25 21:00 by Jerry
    好文章

    # re: 關于ClassLoader In Tomcat 的研究  回復  更多評論   

    2012-02-16 22:21 by cll
    Tomcat 6之后classloader 稍微有些改動了,去掉了server 和 shared, 都有common classloader 來載入了。http://www.jianbozhu.net/2012/02/14/tomcat-classloader-demonstration/ 這篇文章做了個簡單的實驗,比叫有意思。

    Copyright © 久城

    主站蜘蛛池模板: 永久免费av无码入口国语片| 免免费国产AAAAA片| 久久国产亚洲观看| 麻花传媒剧在线mv免费观看| 亚洲精品无码专区| 亚洲色欲久久久综合网| 美女网站免费福利视频| 一本大道一卡二大卡三卡免费| 91亚洲一区二区在线观看不卡| 夫妻免费无码V看片| 最近免费中文字幕中文高清| 2019亚洲午夜无码天堂| 亚洲精品国产字幕久久不卡| 在线免费观看视频你懂的| 久久精品国产影库免费看| 亚洲一线产品二线产品| 亚洲AV无码一区二区三区系列| 免费羞羞视频网站| 最近中文字幕大全免费视频| 污视频网站在线免费看| 亚洲一区二区三区在线观看蜜桃| 不卡精品国产_亚洲人成在线| 无人在线直播免费观看| 在线观看片免费人成视频无码| 亚洲1区1区3区4区产品乱码芒果| 亚洲色精品88色婷婷七月丁香| 成年女性特黄午夜视频免费看| 暖暖在线视频免费视频| 特色特黄a毛片高清免费观看| 亚洲午夜电影在线观看高清| 亚洲精品国产精品乱码不99| 日韩在线a视频免费播放| 亚州免费一级毛片| 免费无码作爱视频| 一级做a爰片久久毛片免费看| 亚洲熟妇无码av另类vr影视| 久久久亚洲AV波多野结衣| 久久精品国产精品亚洲精品| 无码国产亚洲日韩国精品视频一区二区三区 | 成人片黄网站色大片免费观看APP| 久久亚洲精品无码网站|