轉自: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); } }