class Bootstrap

轉自:http://www.huihoo.org/apache/tomcat/heavyz/Bootstrap.java.html
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);

    }


}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章