tomcat(17)启动tomcat
生活随笔
收集整理的這篇文章主要介紹了
tomcat(17)启动tomcat
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
【0】README
1)本文部分文字描述轉自“how tomcat works”,旨在學習“tomcat(17)啟動tomcat”的相關知識;
2)本文重點關注啟動Tomcat時會用到的兩個類,分別是Catalina類和 Bootstrap類;(干貨——引入tomcat啟動時用到了兩個類,分別是Catalina類和 Bootstrap類)
2.1)org.apache.catalina.startup.Catalina類:用于啟動和關閉Server對象,并負責解析Tomcat 配置文件 server.xml; 2.2)org.apache.catalina.startup.Bootstrap類:是一個入口點,負責創建 Catalina實例,并調用其 process()方法;
3)理論上,這兩個類可以合二為一,但為了支持tomcat的多種運行模式,故提供了多種啟動類;
4)用戶只需要運行相應的批處理文件或shell 腳本即可啟動或關閉tomcat;
5)本文會intro 如何在Windows平臺 和 UNIX/Linux 平臺上運行tomcat;
6)本文總結了 tomcat啟動的調用過程,非常干貨,不得不感慨本篇博文產自于收獲的季節.
【1】Catalina類(org.apache.catalina.startup.Catalina) 1)intro:它包含一個Digester類,用于解析位于 %CATALINA_HOME%/conf 目錄下的server.xml 文件;理解到tomcat(15)中 向Digester對象添加規則的原理后,就可以自行配置tomcat了;(干貨——理解到tomcat(15)中 向Digester對象添加規則的原理后,就可以自行配置tomct了,tomcat(15)Digester庫) 1.1)該類還封裝了一個Server對象(服務器組件,你是否有印象):該對象有一個Service對象(服務組件,你是否有印象);(干貨——服務器組件+服務組件,參見tomcat(14)服務器組件和服務組件) 1.2)Service對象包含有一個Servlet容器和一個或多個連接器。所以可以使用Catalina類來啟動或關閉Server對象; 2)可以通過實例化Catalina類,并調用其process()方法來運行tomcat; 3)universe case,即使Catalina類提供了main()方法作為程序的入口點,也需要使用Bootstrap類來實例化process()方法;如下所示: public static void main(String args[]) { // org.apache.catalina.startup.Catalina.main().(new Catalina()).process(args);}public void process(String args[]) { // org.apache.catalina.startup.Catalina.process().setCatalinaHome();setCatalinaBase();try {if (arguments(args)) //highlight line.execute();} catch (Exception e) {e.printStackTrace(System.out);}} protected void setCatalinaHome() {if (System.getProperty("catalina.home") != null)return;System.setProperty("catalina.home",System.getProperty("user.dir"));}protected void setCatalinaBase() {if (System.getProperty("catalina.base") != null)return;System.setProperty("catalina.base",System.getProperty("catalina.home"));} 對以上代碼的分析(Analysis): step1)process()方法設置了兩個系統屬性:catalina.home and catalina.base.catalina.home,默認值均為user.dir 屬性的值; step2)catalina.base == catalina.home ,所以,他們都與 user.dir 屬性的值相同; step3)隨后,process()方法會調用 arguments()方法(highlight line),并傳入參數列表; step4)intro to arguments()方法:arguments()方法處理命令行參數,如果Catalina對象能夠繼續處理的話,arguments()方法返回true; protected boolean arguments(String args[]) {boolean isConfig = false;if (args.length < 1) {usage();return (false);}for (int i = 0; i < args.length; i++) {if (isConfig) {configFile = args[i];isConfig = false;} else if (args[i].equals("-config")) {isConfig = true;} else if (args[i].equals("-debug")) {debug = true;} else if (args[i].equals("-nonaming")) {useNaming = false;} else if (args[i].equals("-help")) {usage();return (false);} else if (args[i].equals("start")) {starting = true;} else if (args[i].equals("stop")) {stopping = true;} else {usage();return (false);}}return (true);} protected void usage() {System.out.println("usage: java org.apache.catalina.startup.Catalina"+ " [ -config {pathname} ] [ -debug ]"+ " [ -nonaming ] { start | stop }");} step5)process()方法會檢查arguments()的返回值是否為true,若為true,則調用execute()方法;該方法會調用start()方法來啟動tomcat, 或調用stop()方法來關閉 tomcat; protected void execute() throws Exception {if (starting)start();else if (stopping)stop();} Attention)以上的分析結果都是基于tomcat4的,在tomcat5中, 會在 process()方法中調用start()方法和 stop()方法; Supplement)本文習慣性的總結了上述調用過程:
【1.1】start()方法 1)源代碼如下: protected void start() { // org.apache.catalina.startup.Catalina.start().// Setting additional variablesif (!useNaming) {System.setProperty("catalina.useNaming", "false");} else {System.setProperty("catalina.useNaming", "true");String value = "org.apache.naming";String oldValue =System.getProperty(javax.naming.Context.URL_PKG_PREFIXES);if (oldValue != null) {value = value + ":" + oldValue;} // String URL_PKG_PREFIXES = "java.naming.factory.url.pkgs";System.setProperty(javax.naming.Context.URL_PKG_PREFIXES, value);value = System.getProperty(javax.naming.Context.INITIAL_CONTEXT_FACTORY);if (value == null) {System.setProperty(javax.naming.Context.INITIAL_CONTEXT_FACTORY,"org.apache.naming.java.javaURLContextFactory");}}// Create and execute our DigesterDigester digester = createStartDigester();File file = configFile();try {InputSource is =new InputSource("file://" + file.getAbsolutePath());FileInputStream fis = new FileInputStream(file);is.setByteStream(fis);digester.push(this);digester.parse(is);fis.close();} catch (Exception e) {System.out.println("Catalina.start using "+ configFile() + ": " + e);e.printStackTrace(System.out);System.exit(1);}// If a SecurityManager is being used, set properties for// checkPackageAccess() and checkPackageDefinitionif( System.getSecurityManager() != null ) {String access = Security.getProperty("package.access");if( access != null && access.length() > 0 )access += ",";elseaccess = "sun.,";Security.setProperty("package.access",access + "org.apache.catalina.,org.apache.jasper.");String definition = Security.getProperty("package.definition");if( definition != null && definition.length() > 0 )definition += ",";elsedefinition = "sun.,";Security.setProperty("package.definition",// FIX ME package "javax." was removed to prevent HotSpot// fatal internal errorsdefinition + "java.,org.apache.catalina.,org.apache.jasper.,org.apache.coyote.");}// Replace System.out and System.err with a custom PrintStreamSystemLogHandler log = new SystemLogHandler(System.out);System.setOut(log);System.setErr(log);Thread shutdownHook = new CatalinaShutdownHook();// Start the new serverif (server instanceof Lifecycle) {try {server.initialize();((Lifecycle) server).start();try {// Register shutdown hookRuntime.getRuntime().addShutdownHook(shutdownHook);} catch (Throwable t) {// This will fail on JDK 1.2. Ignoring, as Tomcat can run// fine without the shutdown hook.}// Wait for the server to be told to shut downserver.await();} catch (LifecycleException e) {System.out.println("Catalina.start: " + e);e.printStackTrace(System.out);if (e.getThrowable() != null) {System.out.println("----- Root Cause -----");e.getThrowable().printStackTrace(System.out);}}}// Shut down the serverif (server instanceof Lifecycle) {try {try {// Remove the ShutdownHook first so that server.stop() // doesn't get invoked twiceRuntime.getRuntime().removeShutdownHook(shutdownHook);} catch (Throwable t) {// This will fail on JDK 1.2. Ignoring, as Tomcat can run// fine without the shutdown hook.}((Lifecycle) server).stop();} catch (LifecycleException e) {System.out.println("Catalina.stop: " + e);e.printStackTrace(System.out);if (e.getThrowable() != null) {System.out.println("----- Root Cause -----");e.getThrowable().printStackTrace(System.out);}}}}
對以上代碼的分析(Analysis): step1)該方法會創建一個Digester實例來解析server.xml(tomcat配置文件);在解析server.xml文件之前,該方法會調用 Digester.push()方法,傳入當前的Catalina對象,這樣,Catalina對象就成了Digester對象的內部棧中的第一個對象; step2)解析server.xml文件后,會使變量Server引用一個Server對象,默認是 org.apache.catalina.core.StandardServer類型的對象; step3)然后,start()方法會調用Server.initialize()方法 和 start()方法; step4)接著,Catalina.start()方法會調用server對象的await()方法,Server對象會使用一個專用的線程來等待關閉命令;await()方法會一直等待直到接收到正確的關閉命令; step5)當await()方法返回時,Catalina.start()方法會調用Server.stop()方法,從而關閉Server對象和其它的組件; Attention) A1)此外,start()方法還會利用關閉鉤子,確保用戶突然退出應用程序時會執行Server.stop()方法; A2)start()方法會調用了createStartDigester 方法創建Digester對象,createStartDigester()方法的源碼如下: protected Digester createStartDigester() {// Initialize the digesterDigester digester = new Digester();digester.setClassLoader(StandardServer.class.getClassLoader());if (debug)digester.setDebug(999);digester.setValidating(false);// Configure the actions we will be usingdigester.addObjectCreate("Server","org.apache.catalina.core.StandardServer","className");digester.addSetProperties("Server");digester.addSetNext("Server","setServer","org.apache.catalina.Server");digester.addObjectCreate("Server/GlobalNamingResources","org.apache.catalina.deploy.NamingResources");digester.addSetProperties("Server/GlobalNamingResources");digester.addSetNext("Server/GlobalNamingResources","setGlobalNamingResources","org.apache.catalina.deploy.NamingResources");digester.addObjectCreate("Server/Listener",null, // MUST be specified in the element"className");digester.addSetProperties("Server/Listener");digester.addSetNext("Server/Listener","addLifecycleListener","org.apache.catalina.LifecycleListener");digester.addObjectCreate("Server/Service","org.apache.catalina.core.StandardService","className");digester.addSetProperties("Server/Service");digester.addSetNext("Server/Service","addService","org.apache.catalina.Service");digester.addObjectCreate("Server/Service/Listener",null, // MUST be specified in the element"className");digester.addSetProperties("Server/Service/Listener");digester.addSetNext("Server/Service/Listener","addLifecycleListener","org.apache.catalina.LifecycleListener");digester.addObjectCreate("Server/Service/Connector","org.apache.catalina.connector.http.HttpConnector","className");digester.addSetProperties("Server/Service/Connector");digester.addSetNext("Server/Service/Connector","addConnector","org.apache.catalina.Connector");digester.addObjectCreate("Server/Service/Connector/Factory","org.apache.catalina.net.DefaultServerSocketFactory","className");digester.addSetProperties("Server/Service/Connector/Factory");digester.addSetNext("Server/Service/Connector/Factory","setFactory","org.apache.catalina.net.ServerSocketFactory");digester.addObjectCreate("Server/Service/Connector/Listener",null, // MUST be specified in the element"className");digester.addSetProperties("Server/Service/Connector/Listener");digester.addSetNext("Server/Service/Connector/Listener","addLifecycleListener","org.apache.catalina.LifecycleListener");// Add RuleSets for nested elementsdigester.addRuleSet(new NamingRuleSet("Server/GlobalNamingResources/"));digester.addRuleSet(new EngineRuleSet("Server/Service/"));digester.addRuleSet(new HostRuleSet("Server/Service/Engine/"));digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Default"));digester.addRuleSet(new NamingRuleSet("Server/Service/Engine/DefaultContext/"));digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Host/Default"));digester.addRuleSet(new NamingRuleSet("Server/Service/Engine/Host/DefaultContext/"));digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Host/"));digester.addRuleSet(new NamingRuleSet("Server/Service/Engine/Host/Context/"));digester.addRule("Server/Service/Engine",new SetParentClassLoaderRule(digester,parentClassLoader));return (digester);} 【1.2】stop()方法 1)intro:stop()方法用來關閉Catalina和Server對象; 2)源代碼: protected void stop() { //org.apache.catalina.startup.Catalina.stop().// Create and execute our DigesterDigester digester = createStopDigester();File file = configFile();try {InputSource is =new InputSource("file://" + file.getAbsolutePath());FileInputStream fis = new FileInputStream(file);is.setByteStream(fis);digester.push(this);digester.parse(is);fis.close();} catch (Exception e) {System.out.println("Catalina.stop: " + e);e.printStackTrace(System.out);System.exit(1);}// Stop the existing servertry {Socket socket = new Socket("127.0.0.1", server.getPort());OutputStream stream = socket.getOutputStream();String shutdown = server.getShutdown();for (int i = 0; i < shutdown.length(); i++)stream.write(shutdown.charAt(i));stream.flush();stream.close();socket.close();} catch (IOException e) {System.out.println("Catalina.stop: " + e);e.printStackTrace(System.out);System.exit(1);}} protected Digester createStopDigester() {// Initialize the digesterDigester digester = new Digester();if (debug)digester.setDebug(999);// Configure the rules we need for shutting downdigester.addObjectCreate("Server","org.apache.catalina.core.StandardServer","className");digester.addSetProperties("Server");digester.addSetNext("Server","setServer","org.apache.catalina.Server");return (digester); } Attention) A1)stop()方法:調用createStopDigester()方法來創建一個 Digester實例,并調用該實例的push()方法,并將當前Catalina對象壓入到 Digester對象的內部棧中,使用Digester對象解析tomcat 的配置文件; A2)然后,stop()方法會向正在運行的Server對象發送關閉命令,以關閉Server對象;
【1.3】啟動Digester對象 1)intro:Catalina.createStartDigester()方法創建了一個 Digester實例,然后為其添加規則,以解析server.xml文件;server.xml文件用來配置 tomcat,位于 ?%CATALINA_HOME%/conf目錄下。添加到Digester對象中的規則是理解tomcat配置的關鍵;(不能再干貨——添加到Digester對象中的關澤是理解tomcat配置的關鍵) 2)org.apache.catalina.startup.Catalina.createStartDigester()的源代碼如上所示: 因為該方法在start()方法中調用,我們在分析start方法的時候,已經分析過了;
對createStartDigester方法源代碼的分析(Analysis): step1)該方法會創建org.apache.commons.digester.Digestser類的實例,并為其添加規則(rules); step2)前3條規則用于解析 server.xml 文件的server元素。下面是為 server 模式添加的規則(因為server元素是跟元素,故又稱為模式): // Configure the actions we will be usingdigester.addObjectCreate("Server","org.apache.catalina.core.StandardServer","className");digester.addSetProperties("Server");digester.addSetNext("Server","setServer","org.apache.catalina.Server"); rule1)第1條規則表明:在遇到server元素時,Digester要創建 StandardServer 類的一個實例; rule2)第2條規則表明:要對 Server對象的指定屬性名設置同名的屬性值; rule3)第3條規則表明:將Server對象壓入到 Digester對象的內部棧中,并與棧中的下一個對象相關聯。 3)下一個對象是Catalina實例,調用其setServer()方法與 Server對象相關聯。那Catalina實例是如何防盜Digester 對象的內部棧中的呢? 在start()方法的開始部分,在解析 server.xml文件之前,會調用 Digester.push()方法將Catalina對象壓入棧: digester.push(this); 【1.4】 關閉Digetster對象 1)intro to createStopDigester()方法:該方法會返回一個 Digester對象來關閉 Server對象; protected Digester createStopDigester() { //org.apache.catalina.startup.createStopDigester().// Initialize the digesterDigester digester = new Digester();if (debug)digester.setDebug(999);// Configure the rules we need for shutting downdigester.addObjectCreate("Server","org.apache.catalina.core.StandardServer","className");digester.addSetProperties("Server");digester.addSetNext("Server","setServer","org.apache.catalina.Server");return (digester);} Attention)與啟動Digester對象不同,關閉Digester對象只對XML 文檔的根元素感興趣;
【2】 Bootstrap類(org.apache.catalina.startup.Bootstrap) 1)intro:該類提供了啟動tomcat的入口點; 2)當運行startup.bat 文件或 startup.sh 文件時,實際上是調用了該類的main()方法。main方法會創建3個類載入器,并實例化Catalina類;然后它調用Catalina.process()方法; 3)Bootstrap類的定義如下: public final class Bootstrap { private static int debug = 0; public static void main(String args[]) {// Set the debug flag appropriatelyfor (int i = 0; i < args.length; i++) {if ("-debug".equals(args[i]))debug = 1;}// Configure catalina.base from catalina.home if not yet setif (System.getProperty("catalina.base") == null)System.setProperty("catalina.base", getCatalinaHome());// Construct the class loaders we will needClassLoader 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);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);unpacked[0] = new File(getCatalinaHome(),"server" + File.separator + "classes");packed[0] = new File(getCatalinaHome(),"server" + File.separator + "lib");catalinaLoader =ClassLoaderFactory.createClassLoader(unpacked, packed,commonLoader);unpacked[0] = new File(getCatalinaBase(),"shared" + File.separator + "classes");packed[0] = new File(getCatalinaBase(),"shared" + File.separator + "lib");sharedLoader =ClassLoaderFactory.createClassLoader(unpacked, packed,commonLoader);} catch (Throwable t) {log("Class loader creation threw exception", t);System.exit(1);}Thread.currentThread().setContextClassLoader(catalinaLoader);// Load our startup class and call its process() methodtry {SecurityClassLoad.securityClassLoad(catalinaLoader);// Instantiate a startup class instanceif (debug >= 1)log("Loading startup class");Class startupClass =catalinaLoader.loadClass("org.apache.catalina.startup.Catalina"); //highlight line.Object startupInstance = startupClass.newInstance();// Set the shared extensions class loaderif (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);// Call the process() method //highlight line.if (debug >= 1)log("Calling startup class process() method");methodName = "process"; //highlight line.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);}} private static String getCatalinaHome() {return System.getProperty("catalina.home",System.getProperty("user.dir"));} private static String getCatalinaBase() {return System.getProperty("catalina.base", getCatalinaHome());} private static void log(String message) {System.out.print("Bootstrap: ");System.out.println(message);} private static void log(String message, Throwable exception) {log(message);exception.printStackTrace(System.out);} } 對以上代碼的分析(Analysis): A1)Bootstrap類有4個靜態方法:兩個log()方法,getCatalinaHome()方法 和 getCatalinaBase()方法; A2)getCatalinaHome()方法:其基本含義是,如果先前沒有設置過catalina.home 屬性的值,它就返回 user.dir屬性的值; A3)?getCatalinaBase()方法:基本含義是,如果catalina.base屬性的值為空,則返回 catalina.home屬性的值; A4)Bootstrap.main()方法中還會為不同目的而創建3個類載入器;使用多個類載入器的目的是為了防止應用程序中的類(包括servlet類和web 應用程序中的其他輔助類)使用 WEB-INF/classes目錄 和 WEB-INF/lib 目錄之外的類。部署到 %CATALINA_HOME%/common/lib 目錄下的那個 JAR 文件的類文件是可以使用的;(干貨——Bootstrap.main()方法中還會為不同目的而創建3個類載入器) 4)對3個類載入器進行詳細說明 4.0)三個類載入器的定義如下: // Construct the class loaders we will need ClassLoader commonLoader = null; ClassLoader catalinaLoader = null; ClassLoader sharedLoader = null; Attention)對于每個類載入器都會指定一條可以訪問的路徑; 4.1)commonLoader類載入器可以載入: %CATALINA_HOME%/common/classes 目錄, %CATALINA_HOME%/common/endorsed 目錄 和 %CATALINA_HOME%/common/lib 目錄下的java類; try {File unpacked[] = new File[1];File packed[] = new File[1];File packed2[] = new File[2];ClassLoaderFactory.setDebug(debug);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); 4.2)catalinaLoader類加載器負責載入運行 Catalina servlet 容器所需要的類。它可以載入: %CATALINA_HOME%/server/classes 目錄,?%CATALINA_HOME%/server/lib 目錄, 以及commonLoader 類載入器可以訪問的所有目錄中的java類; unpacked[0] = new File(getCatalinaHome(),"server" + File.separator + "classes");packed[0] = new File(getCatalinaHome(),"server" + File.separator + "lib");catalinaLoader =ClassLoaderFactory.createClassLoader(unpacked, packed,commonLoader); 4.3)sharedLoader類可以載入: %CATALINA_HOME%/shared/classes 目錄 和?%CATALINA_HOME%/share/lib?目錄以及commonLoader 類載入器可以訪問的所有目錄中的java類; unpacked[0] = new File(getCatalinaBase(),"shared" + File.separator + "classes");packed[0] = new File(getCatalinaBase(),"shared" + File.separator + "lib");sharedLoader =ClassLoaderFactory.createClassLoader(unpacked, packed,commonLoader);} catch (Throwable t) {log("Class loader creation threw exception", t);System.exit(1);} public static ClassLoader createClassLoader(File unpacked[],File packed[],ClassLoader parent)throws Exception { //org.apache.catalina.startup.ClassLoaderFactory.createClassLoader().if (debug >= 1)log("Creating new class loader");// Construct the "class path" for this class loaderArrayList list = new ArrayList();// Add unpacked directoriesif (unpacked != null) {for (int i = 0; i < unpacked.length; i++) {File file = unpacked[i];if (!file.isDirectory() || !file.exists() || !file.canRead())continue;if (debug >= 1)log(" Including directory " + file.getAbsolutePath());URL url = new URL("file", null,file.getCanonicalPath() + File.separator);list.add(url.toString());}}// Add packed directory JAR filesif (packed != null) {for (int i = 0; i < packed.length; i++) {File directory = packed[i];if (!directory.isDirectory() || !directory.exists() ||!directory.canRead())continue;String filenames[] = directory.list();for (int j = 0; j < filenames.length; j++) {String filename = filenames[j].toLowerCase();if (!filename.endsWith(".jar"))continue;File file = new File(directory, filenames[j]);if (debug >= 1)log(" Including jar file " + file.getAbsolutePath());URL url = new URL("file", null,file.getCanonicalPath());list.add(url.toString());}}}// Construct the class loader itselfString array[] = (String[]) list.toArray(new String[list.size()]);StandardClassLoader classLoader = null;if (parent == null)classLoader = new StandardClassLoader(array);elseclassLoader = new StandardClassLoader(array, parent);classLoader.setDelegate(true);return (classLoader);}
Attention) A1)在tomcat中,每個 web 應用程序中與 Context容器相關聯的每個類載入器的父類載入器都是sharedLoader 類載入器; A2)sharedLoader類載入器并不能訪問 Catalina的內部類,或 CLASSPATH 環境變量指定的類路徑中的類; 5)在創建了3個類載入器之后,main()方法會載入Catalina類并創建它的一個實例,然后再將其賦值給 startupInstance 變量: Class startupClass =catalinaLoader.loadClass("org.apache.catalina.startup.Catalina");Object startupInstance = startupClass.newInstance(); 6)然后,它調用setParentClassLoader()方法,并將 sharedLoader類載入器作為參數傳入: // Set the shared extensions class loaderif (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); 7)最后,main()方法會調用 Catalina.process()方法;(for spec info of Catalina.process(), please refer to the supplement of chapter [1]) // Call the process() methodif (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);
【3】在Windows 平臺上運行tomcat 1)可以調用 startup.bat或shutdown.bat?批處理文件來 啟動或關閉 tomcat;
【3.1】如何編寫批處理文件 Attention) A1)首先,批處理文件的后綴名必須是 “.bat”; A2)DOS 目錄及環境變量是區分大小寫的; 0)對批處理命令進行intro(commands): c1)rem: 該命令用于注釋。解釋器將不會執行以rem 命令開始的行; c2)pause:該命令用于暫停正在執行的批處理文件,并提示用戶按某個鍵,然后程序會繼續運行; c3)echo:該命令用于在dos 控制臺上顯示一段文本。例如,下面的命令將在控制臺上輸出“hello world”,然后暫停程序。之所以暫停程序是為了能夠使控制臺將輸出的文本顯示出來; echo hello world pause c3.1)如果想要顯示環境變量的值,需要在其的前后添加 %%;如,下面的目錄將輸出變量myVar的值: echo %myVar% c3.2)如果想要輸出操作系統的名字,可以使用如下的命令: echo %OS% c4)echo off:使用echo off 命令可以防止將批處理文件中的具體命令輸出,而只會輸出執行結果。但是,“echo off”命令本身還是會顯示出來。如果想要將 “echo off”也隱藏起來,需要使用 @echo off 命令; c5)@echo off:該命令與 echo off 命令類似,但是他會連 echo off 命令也隱藏起來; c6)set:用來設置用戶定義或命名的環境變量。在批處理文件中設置的環境變量是臨時存儲在內存中的,在批處理文件執行完成后就會銷毀; 看個荔枝)下面的set命令創建了一個名為 “usernmae”的環境變量,其值為“tang”,并輸出到console:
set username=tang echo %username% pause Attention)為了獲取變量的值,需要在變量前后添加“%”符號。如 “echo %username%”在字符串中就可以取到 username的值; c7)label:使用冒號設置一個標簽。然后可以將標簽傳遞給goto命令,這樣程序就會跳轉到標簽指定的位置。下面的語句定義了一個end的標簽:":end"; c8)goto:goto命令強制批處理文件跳轉到指定標簽所在的位置繼續執行 看個荔枝) echo start goto end echo i am a student; :end echo end pause
對以上腳本的分析(Analysis):在第1行輸出start后,批處理文件會執行 goto命令,跳轉到end標簽處; c9)if:if用來測試條件測試,有3種用法(func):(干貨——if命令用來測試條件測試,有3種用法) if variable==value nextCommand func1)測試變量的值; set myVar=3 if %myVar%==3 echo Correct func2)測試文件是否存在; if exist c:\temp\myFile.txt goto start; func3)測試錯誤值; set myVar=3 if not %myVar%==3 echo Correct
c10)not:not關鍵字用來對一條語句取反; c11)exist:當測試文件是否存在時,會使用到 if 和 exist命令; c12)接收參數:可以給批處理文件傳遞參數,并使用%1 引用第1個參數,%2 引用第2個參數,以此類推; c12.1)echo %1:將在console 輸出 第1個參數的值;(如果批處理文件的名字是 test.bat,并使用 “test hello” 命令來調用它,那么將會在console中輸出 “hello”); 看個荔枝)下面的文件會對第1個參數進行檢查。如果是start,輸出“start”;如果是stop,輸出stop;否則,輸出invalid; echo off if %1==start goto start if %1==stop goto stop go invalid :start echo start go end :stop echo stop goto end :invalid echo invalide :end
Attention)若要檢查運行批處理文件時,是否帶有參數,可以將 %1 與 空字符串進行比較。如,對于下面的批處理文件,如果運行時沒有使用參數,就會在控制臺上輸出“no parameter”; if "%1"=="" echo no parameter orif ""%1""=="""" echo no parameter c13)shift:shift命令用來將參數向后移動一位,即將%2的值復制給%1,%3的值復制給%2,以此類推;例如,下面的代碼使用一條shift命令: echo off shift echo %1 echo %2 如果在運行批處理文件時,附加了3個參數a,b和c,那么上面的命令會有如下輸出: b c 移動之后,要使用 %0 來應用第1個參數,而現在最后一個參數已經失效了; c14)call:該命令用來調用另一條命令; c15)setLocal:在批處理文件中使用 setLocal對環境變量的修改只在當前批處理腳本中有效。當遇到endLocal 命令后,在批處理文件的末尾修改的環境變量的值會恢復成原來的值; c16)start:打開一個新的Windows控制臺,并可以為這個新的控制臺指定一個名字,如:?start "title" ;此外,在 title后面,還有傳入一條將要在新的控制臺中執行的目錄,如下所示: start "title" commandName;
【3.2】 catalina.bat 批處理文件 1)catalina.bat 批處理文件用來啟動或關閉tomcat。另外兩個文件(startup.bat 和 shutdown.bat)提供了更簡單地啟動和關閉tomcat的方法。實際上,startup.bat 和 shutdown.bat 都會調用catalina.bar 文件,并傳入相應的參數; 2)在%CATALINA_HOME%/bin 目錄下,需要以下面的語法格式調用 catalina.bar 腳本: catalina? 或會使用下面的語法 從 %CATALINA_HOME%/bin 目錄下調用該腳本: bin\catalina 3)在兩種case下,參數command 的可選值包括: c1)debug:在調試器中啟動 Catalina; c2)debug -security;在使用安全管理器的case下調試 Catalina; c3)embedded:以嵌入模式啟動Catalina; c4)jpda start:在 JPDA調試器下啟動 Catalina; c5)run:在當前窗口中啟動 Catalina; r6)run -security:在當前窗口中,通過安全管理器啟動 Catalina; r7)start:在新窗口中啟動 Catalina; r8)start -security:在新窗口中通過安全管理器啟動 Catalina; r9)stop:關閉Catalina; 看個荔枝)想在新窗口中啟動 Catalina,可以使用如下命令:catalina start;
4)catalina.bat 批處理文件的內容: ?https://github.com/pacosonTang/HowTomcatWorks/blob/master/chapter17/catalina.bat 對catalina.bat 文件的分析(Analysis):暫時省略
Supplement) Supplement1)catalina.bat 文件中,通過設置MAINCLASS==org.apache.catalina.startup.Bootstrap,然后在該bat文件末尾會運行該類(Bootstrap) set MAINCLASS=org.apache.catalina.startup.Bootstrap // line 203rem Execute Java with the applicable properties //line 307. if not "%JPDA%" == "" goto doJpda if not "%SECURITY_POLICY_FILE%" == "" goto doSecurity %_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION% goto end :doSecurity %_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Djava.security.manager -Djava.security.policy=="%SECURITY_POLICY_FILE%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION% goto end :doJpda if not "%SECURITY_POLICY_FILE%" == "" goto doSecurityJpda %_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %JPDA_OPTS% %DEBUG_OPTS% -Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION% goto end :doSecurityJpda %_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %JPDA_OPTS% %DEBUG_OPTS% -Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Djava.security.manager -Djava.security.policy=="%SECURITY_POLICY_FILE%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION% goto end // line 321Supplement2) 總結tomcat啟動steps(不能再干貨) step1)startup.bat 批處理文件會調用 catalina.bat 文件,而catalina.bat批處理會運行org.apache.catalina.startup.Bootstrap 類(main方法); step2)Bootstrap.main()方法會調用 Catalina.process()方法; public final class Bootstrap { //org.apache.catalina.startup.Bootstrapprivate static int debug = 0; public static void main(String args[]) {// Set the debug flag appropriatelyfor (int i = 0; i < args.length; i++) {if ("-debug".equals(args[i]))debug = 1;}// Configure catalina.base from catalina.home if not yet setif (System.getProperty("catalina.base") == null)System.setProperty("catalina.base", getCatalinaHome());// Construct the class loaders we will needClassLoader 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);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);unpacked[0] = new File(getCatalinaHome(),"server" + File.separator + "classes");packed[0] = new File(getCatalinaHome(),"server" + File.separator + "lib");catalinaLoader =ClassLoaderFactory.createClassLoader(unpacked, packed,commonLoader);unpacked[0] = new File(getCatalinaBase(),"shared" + File.separator + "classes");packed[0] = new File(getCatalinaBase(),"shared" + File.separator + "lib");sharedLoader =ClassLoaderFactory.createClassLoader(unpacked, packed,commonLoader);} catch (Throwable t) {log("Class loader creation threw exception", t);System.exit(1);}Thread.currentThread().setContextClassLoader(catalinaLoader);// Load our startup class and call its process() methodtry {SecurityClassLoad.securityClassLoad(catalinaLoader);// Instantiate a startup class instanceif (debug >= 1)log("Loading startup class");Class startupClass =catalinaLoader.loadClass("org.apache.catalina.startup.Catalina"); //highlight line.Object startupInstance = startupClass.newInstance(); // 創建Catalina類的實例.// Set the shared extensions class loaderif (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);// Call the process() method //highlight line.if (debug >= 1)log("Calling startup class process() method");methodName = "process"; //highlight line.paramTypes = new Class[1];paramTypes[0] = args.getClass();paramValues = new Object[1];paramValues[0] = args;method =startupInstance.getClass().getMethod(methodName, paramTypes); // 調用Catalina.process()方法.method.invoke(startupInstance, paramValues);} catch (Exception e) {System.out.println("Exception during startup processing");e.printStackTrace(System.out);System.exit(2);}} private static String getCatalinaHome() {return System.getProperty("catalina.home",System.getProperty("user.dir"));} private static String getCatalinaBase() {return System.getProperty("catalina.base", getCatalinaHome());} private static void log(String message) {System.out.print("Bootstrap: ");System.out.println(message);} private static void log(String message, Throwable exception) {log(message);exception.printStackTrace(System.out);} } Attention)文末會對createStateDigester()方法的調用過程進一步總結;(限于篇幅)
<?xml version='1.0' encoding='utf-8'?> <!--conf/server.xml源碼如下 --> <!--Licensed to the Apache Software Foundation (ASF) under one or morecontributor license agreements. See the NOTICE file distributed withthis work for additional information regarding copyright ownership.The ASF licenses this file to You under the Apache License, Version 2.0(the "License"); you may not use this file except in compliance withthe License. You may obtain a copy of the License athttp://www.apache.org/licenses/LICENSE-2.0Unless required by applicable law or agreed to in writing, softwaredistributed under the License is distributed on an "AS IS" BASIS,WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.See the License for the specific language governing permissions andlimitations under the License. --> <!-- Note: A "Server" is not itself a "Container", so you may notdefine subcomponents such as "Valves" at this level.Documentation at /docs/config/server.html--> <Server port="8005" shutdown="SHUTDOWN"><!-- Security listener. Documentation at /docs/config/listeners.html<Listener className="org.apache.catalina.security.SecurityListener" />--><!--APR library loader. Documentation at /docs/apr.html --><Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" /><!--Initialize Jasper prior to webapps are loaded. Documentation at /docs/jasper-howto.html --><Listener className="org.apache.catalina.core.JasperListener" /><!-- Prevent memory leaks due to use of particular java/javax APIs--><Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" /><Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" /><Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" /><!-- Global JNDI resourcesDocumentation at /docs/jndi-resources-howto.html--><GlobalNamingResources><!-- Editable user database that can also be used byUserDatabaseRealm to authenticate users--><Resource name="UserDatabase" auth="Container"type="org.apache.catalina.UserDatabase"description="User database that can be updated and saved"factory="org.apache.catalina.users.MemoryUserDatabaseFactory"pathname="conf/tomcat-users.xml" /></GlobalNamingResources><!-- A "Service" is a collection of one or more "Connectors" that sharea single "Container" Note: A "Service" is not itself a "Container",so you may not define subcomponents such as "Valves" at this level.Documentation at /docs/config/service.html--><Service name="Catalina"><!--The connectors can use a shared executor, you can define one or more named thread pools--><!--<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"maxThreads="150" minSpareThreads="4"/>--><!-- A "Connector" represents an endpoint by which requests are receivedand responses are returned. Documentation at :Java HTTP Connector: /docs/config/http.html (blocking & non-blocking)Java AJP Connector: /docs/config/ajp.htmlAPR (HTTP/AJP) Connector: /docs/apr.htmlDefine a non-SSL HTTP/1.1 Connector on port 8080--><Connector port="8888" protocol="HTTP/1.1"connectionTimeout="20000"redirectPort="8443" /><!-- A "Connector" using the shared thread pool--><!--<Connector executor="tomcatThreadPool"port="8080" protocol="HTTP/1.1"connectionTimeout="20000"redirectPort="8443" />--><!-- Define a SSL HTTP/1.1 Connector on port 8443This connector uses the JSSE configuration, when using APR, theconnector should be using the OpenSSL style configurationdescribed in the APR documentation --><!--<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"maxThreads="150" scheme="https" secure="true"clientAuth="false" sslProtocol="TLS" />--><!-- Define an AJP 1.3 Connector on port 8009 --><Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /><!-- An Engine represents the entry point (within Catalina) that processesevery request. The Engine implementation for Tomcat stand aloneanalyzes the HTTP headers included with the request, and passes themon to the appropriate Host (virtual host).Documentation at /docs/config/engine.html --><!-- You should set jvmRoute to support load-balancing via AJP ie :<Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm1">--><Engine name="Catalina" defaultHost="localhost"><!--For clustering, please take a look at documentation at:/docs/cluster-howto.html (simple how to)/docs/config/cluster.html (reference documentation) --><!--<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>--><!-- Use the LockOutRealm to prevent attempts to guess user passwordsvia a brute-force attack --><Realm className="org.apache.catalina.realm.LockOutRealm"><!-- This Realm uses the UserDatabase configured in the global JNDIresources under the key "UserDatabase". Any editsthat are performed against this UserDatabase are immediatelyavailable for use by the Realm. --><Realm className="org.apache.catalina.realm.UserDatabaseRealm"resourceName="UserDatabase"/></Realm><Host name="localhost" appBase="webapps"unpackWARs="true" autoDeploy="true"><!-- SingleSignOn valve, share authentication between web applicationsDocumentation at: /docs/config/valve.html --><!--<Valve className="org.apache.catalina.authenticator.SingleSignOn" />--><!-- Access log processes all example.Documentation at: /docs/config/valve.htmlNote: The pattern used is equivalent to using pattern="common" --><Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"prefix="localhost_access_log." suffix=".txt"pattern="%h %l %u %t "%r" %s %b" /></Host></Engine></Service> </Server> 對以上server.xml代碼的分析(Analysis): A1)創建一個服務器組件; A1.1)服務器組件里面注入多個監聽器,資源(GlobalNamingResources) A1.2)創建一個服務組件; A1.2.1)創建兩個Connector; A1.2.2)創建一個Engine,Engine中注入兩個領域對象(Realm);還注入了一個Host容器;和一個閥; Attention) A1)服務器組件和服務組件,參見 tomcat(14)服務器組件和服務組件; A2)Digester用于將XML 文檔中的元素轉換成 java 對象,參見?tomcat(15)Digester庫
【3.3】在Windows 平臺上啟動tomcat(startup.bat 文件調用catalina.bat 文件時,會傳入參數 start) https://github.com/pacosonTang/HowTomcatWorks/blob/master/chapter17/startup.bat
【3.4】在Windows 平臺上關閉tomcat(shutdown.bat 文件調用 catalina.bat文件時,傳入參數 stop) https://github.com/pacosonTang/HowTomcatWorks/blob/master/chapter17/shutdown.bat
【4】在Linux平臺上啟動Tomcat 1)在linux平臺上,tomcat使用shell 腳本來啟動和關閉。shell腳本的后綴名可以是 “.sh”,位于 $CATALINA_HOME/bin 目錄下; 2)intro:本章節將intro 4 個腳本:catalina.sh, statup.sh, shutdown.sh, setclasspath.sh;
【4.1】如何編寫UNIX/Linux Shell腳本 1)intro:shell腳本是由解釋器逐行執行的,shell 腳本的擴展名可有可無,但最常用的擴展名是 .sh; 2)下面簡單介紹下 shell 命令(command): c1)注釋:shell腳本使用 # 符號來表示注釋內容; c2)clear:使用該命令來清空屏幕; c3)exit:該命令可以用來退出當前shell 腳本的執行;一般case下,exit后面都會附加一個退出狀態,其中0 表示shell腳本正常執行完成,非0值表示shell異常退出;如果因為程序運行中的某種異常而想退出,使用如下命令:exit 1;(干貨——exit后面都會附加一個退出狀態,其中0 表示shell腳本正常執行完成,非0值表示shell異常退出) c4)echo:該命令可以向屏幕輸出一個字符串:echo hello world; c5)調用函數:可以使用句點(.)來調用一個函數,或執行另一個shell 腳本; c6)系統變量與用于自定義變量:變量名必須以字母,數字或下劃線開頭,使用等號就可以定義一個變量;如下面的命令定義了一個名為 myVar 的變量,其值為 Tootsie:myVar=Toosie; Attention) A1)等號的前后一定不能有空格。此外,shell 腳本對變量名是區分大小寫的 ; A2)若想定義一個值為NULL的變量,可使用空字符串為其賦值,或在等號右邊留空即可: myVar= myVar="" A3)若想要獲取變量的值,需要在變量前面加上美元符號($):echo $myVar A4)Unix/Linux 提供了一些系統變量供用戶使用;如,變量HOME 保存了當前用戶的主目錄,變量PWD 保存了用戶當前所在的目錄,變量PATH 保存了將會在哪些地方查找要執行的命令等; c7)expr: 可以使用該命令來計算一個表達式的值。表達式必須以反引號引用;如下面的shell 腳本計算一個數學表達式: sum=`expr 100+200` echo $sum c7.1)腳本:echo `expr 200+300` 會輸出500; c7.2)特殊表達式`uname`會得到操作系統的名稱:echo `uname` 會輸出操作系統名稱(Linux或Unix); c7.3)特殊表達式 `dirname filePath` 會返回指定文件所在的目錄。如,命令 `dirname /home/user1/test.sh` 會返回“home/user1”; c8)訪問參數:如同向函數中傳入參數一樣,也可以向shell腳本傳入參數,并使用 $1 來引用第1個參數,$2引用第2個參數,以此類推;$# 會返回參數的格式,$@會返回所有的參數; c9)shift:這條命令會將參數向后移動一位,$1的值改為 $2, $2的值改為$3, 以此類推; c10)if...then...[else...] fi:if 語句用來測試條件,并執行相應的命令列表。它的語法格式如下: if condition thenlist of commands [elselist of commands ] fi Attention)也可以使用 “elif”來代替“else if”; 看個荔枝)如下面的shell腳本,若傳入的第1個參數是 “start”,運行下面的腳本,會輸出“start”;如果傳入的第1個參數是 “stop”,則輸出“stop”;
if [ "$1" = "start" ]; thenecho start fi if [ "$1" = "end" ]; thenecho end fi Attention)
A1)判斷條件在 “[” 后面必須有一個空格, 在“]”前面也必須有一個空格; A2)將 $1 用雙引號引起來可以防止解釋器在發現調用腳本時沒有使用參數而拋出異常; A3)$0:表示的是用來調用該腳本的命令。如,使用下面的命令來調用一個名為 test.sh 的腳本:./test.sh; 那么,$0 返回 “./test.sh”;下面是一些用來進行條件判斷的測試選項: -f file:當存在文件file時,為true; -r file:當文件file可讀時,為true; -z string:如果string 是空字符串,為 true; -n string:如果string 不為空字符串,為true; string1 = string2:如果string1 等于string2,為true; string1 != string2:如果string1 不等于 string2,為true; c11)for循環:使用for循環來重復執行一些命令: for {var} in {list} dolist of commands done 看個荔枝)
for i in 1 2 3 doecho i=$i done output: i1 i2 i3 c12)while循環: while [condition] dolist of commands done
看個荔枝)
n=1 while [$n -lt 3] doecho i $n done output: i1 i2 Attention)其中 [$n -lt 3];中 -lt 的意思是小于3,(lt == less than) c13)case:case結構表示可以在程序中執行一些選擇過程。其語法格式如下所示: case $variable-name in pattern1)list of commands;; pattern2)list of commands;; *)list of commands;; esac Attention)“;;”表示命令列表執行完成,如果上面的模式都不匹配時,“*)”表示所要執行的命令; 看個荔枝) case "`uname`" inCYGWIN*)echo cygwin;;OS400*)echo os400;;LINUX*)echo linux;;*)echo os not recognized;; esac c14)輸出重定向(review):使用 “>”將輸出重定向到一個文件;(echo hello > myFile.txt);這會創建一個 myFile.txt的文件,并將 hello 寫入到其中,不會向屏幕上輸出文字; Supplement) S1)"1>&2":會把標準輸出上的錯誤消息重定向到標準錯誤中; S1)"2>&1":會把標準錯誤中的信息重新向到 標準輸出中;
c15)條件執行:可以使用命令或條件來決定是否執行另一條命令。在這種 case下, 可以使用 && 或 || ,如下所示: c15.1)command1 && command2:如果command1返回的退出狀態是0,那么會執行command2;(0表true,非0表false) c15.2)command1 || command2:如果command1返回的退出狀態是非0,那么會執行command2;(0表true,非0表false) c15.3)command1 && command2 || command3:如果command1返回的退出狀態是非0,那么會執行command2;否則,執行command3;(0表true,非0表false);
【4.2】catalina.sh 腳本 1)intro: 該文件用來在 UNIX/Linux 平臺上啟動或關閉tomcat。若要啟動tomcat,需要將 start作為第1個參數傳遞給 catalina.sh 腳本。若要關閉 tomcat,需要將stop 作為第1個參數傳遞給 catalina.sh腳本。下面是有效的 參數列表(parameters): p1)debug:在調試器中啟動catalina;(在OS400系統上不可用) p2)debug -security:通過安全管理器調試catalina;(在OS400系統上不可用) p3)embedded:以嵌入模式啟動 Catalina; p4)jpda start:在JPDA 調試器下啟動 Catalina; p5)run:在當前窗口中啟動 Catalina; p6)run -security:在安全管理器下,使用當前窗口啟動 catalina; p7)start:使用一個新窗口啟動 catalina; p8)start -security:在安全管理器下,使用一個新窗口啟動 catalina; p9)stop:關閉 catalina; 2)catalina.sh 的源代碼,參見: ?https://github.com/pacosonTang/HowTomcatWorks/blob/master/chapter17/catalina.sh
【4.3】在 unix/linux 平臺上啟動 tomcat 1)使用 startup.sh 腳本可以方便地啟動 tomcat。startup.sh 腳本會設置正確的環境變量,然后調用 catalina.sh腳本,并傳入參數 start: ?https://github.com/pacosonTang/HowTomcatWorks/blob/master/chapter17/startup.sh
【4.4】在 unix/linux 平臺上關閉 tomcat 1)使用 shutdown.sh 腳本可以方便地啟動 tomcat。shutdown.sh 腳本會設置正確的環境變量,然后調用 catalina.sh腳本,并傳入參數 stop: ?https://github.com/pacosonTang/HowTomcatWorks/blob/master/chapter17/shutdown.sh
------------------------------------------------------------------------------------------------------ Supplement)文末繼續對 Catatalina.createStateDigester()方法的調用過程進一步總結 protected Digester createStartDigester() { //org.apache.catalina.startup.Catalina.createStartDigester().// Initialize the digesterDigester digester = new Digester();digester.setClassLoader(StandardServer.class.getClassLoader());if (debug)digester.setDebug(999);digester.setValidating(false);// Configure the actions we will be usingdigester.addObjectCreate("Server","org.apache.catalina.core.StandardServer","className");digester.addSetProperties("Server");digester.addSetNext("Server","setServer","org.apache.catalina.Server");digester.addObjectCreate("Server/GlobalNamingResources","org.apache.catalina.deploy.NamingResources");digester.addSetProperties("Server/GlobalNamingResources");digester.addSetNext("Server/GlobalNamingResources","setGlobalNamingResources","org.apache.catalina.deploy.NamingResources");digester.addObjectCreate("Server/Listener",null, // MUST be specified in the element"className");digester.addSetProperties("Server/Listener");digester.addSetNext("Server/Listener","addLifecycleListener","org.apache.catalina.LifecycleListener");digester.addObjectCreate("Server/Service","org.apache.catalina.core.StandardService","className");digester.addSetProperties("Server/Service");digester.addSetNext("Server/Service","addService","org.apache.catalina.Service");digester.addObjectCreate("Server/Service/Listener",null, // MUST be specified in the element"className");digester.addSetProperties("Server/Service/Listener");digester.addSetNext("Server/Service/Listener","addLifecycleListener","org.apache.catalina.LifecycleListener");digester.addObjectCreate("Server/Service/Connector","org.apache.catalina.connector.http.HttpConnector","className");digester.addSetProperties("Server/Service/Connector");digester.addSetNext("Server/Service/Connector","addConnector","org.apache.catalina.Connector");digester.addObjectCreate("Server/Service/Connector/Factory","org.apache.catalina.net.DefaultServerSocketFactory","className");digester.addSetProperties("Server/Service/Connector/Factory");digester.addSetNext("Server/Service/Connector/Factory","setFactory","org.apache.catalina.net.ServerSocketFactory");digester.addObjectCreate("Server/Service/Connector/Listener",null, // MUST be specified in the element"className");digester.addSetProperties("Server/Service/Connector/Listener");digester.addSetNext("Server/Service/Connector/Listener","addLifecycleListener","org.apache.catalina.LifecycleListener");// Add RuleSets for nested elementsdigester.addRuleSet(new NamingRuleSet("Server/GlobalNamingResources/"));digester.addRuleSet(new EngineRuleSet("Server/Service/")); //highlight line.digester.addRuleSet(new HostRuleSet("Server/Service/Engine/")); //highlight line.digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Default")); //highlight line.digester.addRuleSet(new NamingRuleSet("Server/Service/Engine/DefaultContext/"));digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Host/Default"));digester.addRuleSet(new NamingRuleSet("Server/Service/Engine/Host/DefaultContext/"));digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Host/"));digester.addRuleSet(new NamingRuleSet("Server/Service/Engine/Host/Context/"));digester.addRule("Server/Service/Engine",new SetParentClassLoaderRule(digester,parentClassLoader));return (digester);} public void addRuleInstances(Digester digester) { //org.apache.catalina.startup.EngineRuleSet.addRuleInstances().digester.addObjectCreate(prefix + "Engine","org.apache.catalina.core.StandardEngine","className");digester.addSetProperties(prefix + "Engine");digester.addRule(prefix + "Engine",new LifecycleListenerRule(digester,"org.apache.catalina.startup.EngineConfig","engineConfigClass"));digester.addSetNext(prefix + "Engine","setContainer","org.apache.catalina.Container");digester.addObjectCreate(prefix + "Engine/Listener",null, // MUST be specified in the element"className");digester.addSetProperties(prefix + "Engine/Listener");digester.addSetNext(prefix + "Engine/Listener","addLifecycleListener","org.apache.catalina.LifecycleListener");digester.addObjectCreate(prefix + "Engine/Logger",null, // MUST be specified in the element"className");digester.addSetProperties(prefix + "Engine/Logger");digester.addSetNext(prefix + "Engine/Logger","setLogger","org.apache.catalina.Logger");digester.addObjectCreate(prefix + "Engine/Realm",null, // MUST be specified in the element"className");digester.addSetProperties(prefix + "Engine/Realm");digester.addSetNext(prefix + "Engine/Realm","setRealm","org.apache.catalina.Realm");digester.addObjectCreate(prefix + "Engine/Valve",null, // MUST be specified in the element"className");digester.addSetProperties(prefix + "Engine/Valve");digester.addSetNext(prefix + "Engine/Valve","addValve","org.apache.catalina.Valve");}public void addRuleInstances(Digester digester) { //org.apache.catalina.startup.HostRuleSet.addRuleInstances().digester.addObjectCreate(prefix + "Host","org.apache.catalina.core.StandardHost","className");digester.addSetProperties(prefix + "Host");digester.addRule(prefix + "Host",new CopyParentClassLoaderRule(digester));digester.addRule(prefix + "Host",new LifecycleListenerRule(digester,"org.apache.catalina.startup.HostConfig","hostConfigClass"));digester.addSetNext(prefix + "Host","addChild","org.apache.catalina.Container");digester.addCallMethod(prefix + "Host/Alias","addAlias", 0);digester.addObjectCreate(prefix + "Host/Cluster",null, // MUST be specified in the element"className");digester.addSetProperties(prefix + "Host/Cluster");digester.addSetNext(prefix + "Host/Cluster","addCluster","org.apache.catalina.Cluster");digester.addObjectCreate(prefix + "Host/Listener",null, // MUST be specified in the element"className");digester.addSetProperties(prefix + "Host/Listener");digester.addSetNext(prefix + "Host/Listener","addLifecycleListener","org.apache.catalina.LifecycleListener");digester.addObjectCreate(prefix + "Host/Logger",null, // MUST be specified in the element"className");digester.addSetProperties(prefix + "Host/Logger");digester.addSetNext(prefix + "Host/Logger","setLogger","org.apache.catalina.Logger");digester.addObjectCreate(prefix + "Host/Realm",null, // MUST be specified in the element"className");digester.addSetProperties(prefix + "Host/Realm");digester.addSetNext(prefix + "Host/Realm","setRealm","org.apache.catalina.Realm");digester.addObjectCreate(prefix + "Host/Valve",null, // MUST be specified in the element"className");digester.addSetProperties(prefix + "Host/Valve");digester.addSetNext(prefix + "Host/Valve","addValve","org.apache.catalina.Valve");}public void addRuleInstances(Digester digester) { //<span style="font-family:Arial, Helvetica, sans-serif;"> org.apache.catalina.ContextRuleSet.addRuleInstances().</span>if (!isDefaultContext()) {digester.addObjectCreate(prefix + "Context","org.apache.catalina.core.StandardContext","className");} else {digester.addObjectCreate(prefix + "Context","org.apache.catalina.core.StandardDefaultContext","className");}digester.addSetProperties(prefix + "Context");if (!isDefaultContext()) {digester.addRule(prefix + "Context",new CopyParentClassLoaderRule(digester));digester.addRule(prefix + "Context",new LifecycleListenerRule(digester,"org.apache.catalina.startup.ContextConfig","configClass"));digester.addSetNext(prefix + "Context","addChild","org.apache.catalina.Container");digester.addRule(prefix + "Context",new ContextValidatorRule(digester));} else {digester.addSetNext(prefix + "Context","addDefaultContext","org.apache.catalina.DefaultContext");}digester.addCallMethod(prefix + "Context/InstanceListener","addInstanceListener", 0);digester.addObjectCreate(prefix + "Context/Listener",null, // MUST be specified in the element"className");digester.addSetProperties(prefix + "Context/Listener");digester.addSetNext(prefix + "Context/Listener","addLifecycleListener","org.apache.catalina.LifecycleListener");digester.addRule(prefix + "Context/Loader",new CreateLoaderRule(digester,"org.apache.catalina.loader.WebappLoader","className"));digester.addSetProperties(prefix + "Context/Loader");digester.addSetNext(prefix + "Context/Loader","setLoader","org.apache.catalina.Loader");digester.addObjectCreate(prefix + "Context/Logger",null, // MUST be specified in the element"className");digester.addSetProperties(prefix + "Context/Logger");digester.addSetNext(prefix + "Context/Logger","setLogger","org.apache.catalina.Logger");digester.addObjectCreate(prefix + "Context/Manager","org.apache.catalina.session.StandardManager","className");digester.addSetProperties(prefix + "Context/Manager");digester.addSetNext(prefix + "Context/Manager","setManager","org.apache.catalina.Manager");digester.addObjectCreate(prefix + "Context/Manager/Store",null, // MUST be specified in the element"className");digester.addSetProperties(prefix + "Context/Manager/Store");digester.addSetNext(prefix + "Context/Manager/Store","setStore","org.apache.catalina.Store");digester.addObjectCreate(prefix + "Context/Parameter","org.apache.catalina.deploy.ApplicationParameter");digester.addSetProperties(prefix + "Context/Parameter");digester.addSetNext(prefix + "Context/Parameter","addApplicationParameter","org.apache.catalina.deploy.ApplicationParameter");digester.addObjectCreate(prefix + "Context/Realm",null, // MUST be specified in the element"className");digester.addSetProperties(prefix + "Context/Realm");digester.addSetNext(prefix + "Context/Realm","setRealm","org.apache.catalina.Realm");digester.addObjectCreate(prefix + "Context/ResourceLink","org.apache.catalina.deploy.ContextResourceLink");digester.addSetProperties(prefix + "Context/ResourceLink");digester.addSetNext(prefix + "Context/ResourceLink","addResourceLink","org.apache.catalina.deploy.ContextResourceLink");digester.addObjectCreate(prefix + "Context/Resources","org.apache.naming.resources.FileDirContext","className");digester.addSetProperties(prefix + "Context/Resources");digester.addSetNext(prefix + "Context/Resources","setResources","javax.naming.directory.DirContext");digester.addObjectCreate(prefix + "Context/Valve",null, // MUST be specified in the element"className");digester.addSetProperties(prefix + "Context/Valve");digester.addSetNext(prefix + "Context/Valve","addValve","org.apache.catalina.Valve");digester.addCallMethod(prefix + "Context/WrapperLifecycle","addWrapperLifecycle", 0);digester.addCallMethod(prefix + "Context/WrapperListener","addWrapperListener", 0);}?對以上代碼的分析(Analysis): A1)EngineRuleSet.addRuleInstances()方法:創建Engine容器StandardEngine,Engine監聽器EngineConfig, 聲明周期監聽器?LifecycleListener, 日志Logger, 領域對象Realm, 管道閥對象?Valve; A2)HostRuleSet.addRuleInstances()方法:創建Host容器StandardHost, Host監聽器HostConfig, 集群Cluster, 生命周期監聽器LifecycleListener,?日志Logger, 領域對象Realm, 管道閥對象?Valve; A3)ContextRuleSet.addRuleInstances()方法:創建Context容器?StandardContext, Context監聽器ContextConfig, 生命周期監聽器LifecycleListener,Web加載器WebappLoader, 管理器Manager,?Store, 領域對象Realm,?ContextResourceLink, 管道閥對象Valve,
【1】Catalina類(org.apache.catalina.startup.Catalina) 1)intro:它包含一個Digester類,用于解析位于 %CATALINA_HOME%/conf 目錄下的server.xml 文件;理解到tomcat(15)中 向Digester對象添加規則的原理后,就可以自行配置tomcat了;(干貨——理解到tomcat(15)中 向Digester對象添加規則的原理后,就可以自行配置tomct了,tomcat(15)Digester庫) 1.1)該類還封裝了一個Server對象(服務器組件,你是否有印象):該對象有一個Service對象(服務組件,你是否有印象);(干貨——服務器組件+服務組件,參見tomcat(14)服務器組件和服務組件) 1.2)Service對象包含有一個Servlet容器和一個或多個連接器。所以可以使用Catalina類來啟動或關閉Server對象; 2)可以通過實例化Catalina類,并調用其process()方法來運行tomcat; 3)universe case,即使Catalina類提供了main()方法作為程序的入口點,也需要使用Bootstrap類來實例化process()方法;如下所示: public static void main(String args[]) { // org.apache.catalina.startup.Catalina.main().(new Catalina()).process(args);}public void process(String args[]) { // org.apache.catalina.startup.Catalina.process().setCatalinaHome();setCatalinaBase();try {if (arguments(args)) //highlight line.execute();} catch (Exception e) {e.printStackTrace(System.out);}} protected void setCatalinaHome() {if (System.getProperty("catalina.home") != null)return;System.setProperty("catalina.home",System.getProperty("user.dir"));}protected void setCatalinaBase() {if (System.getProperty("catalina.base") != null)return;System.setProperty("catalina.base",System.getProperty("catalina.home"));} 對以上代碼的分析(Analysis): step1)process()方法設置了兩個系統屬性:catalina.home and catalina.base.catalina.home,默認值均為user.dir 屬性的值; step2)catalina.base == catalina.home ,所以,他們都與 user.dir 屬性的值相同; step3)隨后,process()方法會調用 arguments()方法(highlight line),并傳入參數列表; step4)intro to arguments()方法:arguments()方法處理命令行參數,如果Catalina對象能夠繼續處理的話,arguments()方法返回true; protected boolean arguments(String args[]) {boolean isConfig = false;if (args.length < 1) {usage();return (false);}for (int i = 0; i < args.length; i++) {if (isConfig) {configFile = args[i];isConfig = false;} else if (args[i].equals("-config")) {isConfig = true;} else if (args[i].equals("-debug")) {debug = true;} else if (args[i].equals("-nonaming")) {useNaming = false;} else if (args[i].equals("-help")) {usage();return (false);} else if (args[i].equals("start")) {starting = true;} else if (args[i].equals("stop")) {stopping = true;} else {usage();return (false);}}return (true);} protected void usage() {System.out.println("usage: java org.apache.catalina.startup.Catalina"+ " [ -config {pathname} ] [ -debug ]"+ " [ -nonaming ] { start | stop }");} step5)process()方法會檢查arguments()的返回值是否為true,若為true,則調用execute()方法;該方法會調用start()方法來啟動tomcat, 或調用stop()方法來關閉 tomcat; protected void execute() throws Exception {if (starting)start();else if (stopping)stop();} Attention)以上的分析結果都是基于tomcat4的,在tomcat5中, 會在 process()方法中調用start()方法和 stop()方法; Supplement)本文習慣性的總結了上述調用過程:
【1.1】start()方法 1)源代碼如下: protected void start() { // org.apache.catalina.startup.Catalina.start().// Setting additional variablesif (!useNaming) {System.setProperty("catalina.useNaming", "false");} else {System.setProperty("catalina.useNaming", "true");String value = "org.apache.naming";String oldValue =System.getProperty(javax.naming.Context.URL_PKG_PREFIXES);if (oldValue != null) {value = value + ":" + oldValue;} // String URL_PKG_PREFIXES = "java.naming.factory.url.pkgs";System.setProperty(javax.naming.Context.URL_PKG_PREFIXES, value);value = System.getProperty(javax.naming.Context.INITIAL_CONTEXT_FACTORY);if (value == null) {System.setProperty(javax.naming.Context.INITIAL_CONTEXT_FACTORY,"org.apache.naming.java.javaURLContextFactory");}}// Create and execute our DigesterDigester digester = createStartDigester();File file = configFile();try {InputSource is =new InputSource("file://" + file.getAbsolutePath());FileInputStream fis = new FileInputStream(file);is.setByteStream(fis);digester.push(this);digester.parse(is);fis.close();} catch (Exception e) {System.out.println("Catalina.start using "+ configFile() + ": " + e);e.printStackTrace(System.out);System.exit(1);}// If a SecurityManager is being used, set properties for// checkPackageAccess() and checkPackageDefinitionif( System.getSecurityManager() != null ) {String access = Security.getProperty("package.access");if( access != null && access.length() > 0 )access += ",";elseaccess = "sun.,";Security.setProperty("package.access",access + "org.apache.catalina.,org.apache.jasper.");String definition = Security.getProperty("package.definition");if( definition != null && definition.length() > 0 )definition += ",";elsedefinition = "sun.,";Security.setProperty("package.definition",// FIX ME package "javax." was removed to prevent HotSpot// fatal internal errorsdefinition + "java.,org.apache.catalina.,org.apache.jasper.,org.apache.coyote.");}// Replace System.out and System.err with a custom PrintStreamSystemLogHandler log = new SystemLogHandler(System.out);System.setOut(log);System.setErr(log);Thread shutdownHook = new CatalinaShutdownHook();// Start the new serverif (server instanceof Lifecycle) {try {server.initialize();((Lifecycle) server).start();try {// Register shutdown hookRuntime.getRuntime().addShutdownHook(shutdownHook);} catch (Throwable t) {// This will fail on JDK 1.2. Ignoring, as Tomcat can run// fine without the shutdown hook.}// Wait for the server to be told to shut downserver.await();} catch (LifecycleException e) {System.out.println("Catalina.start: " + e);e.printStackTrace(System.out);if (e.getThrowable() != null) {System.out.println("----- Root Cause -----");e.getThrowable().printStackTrace(System.out);}}}// Shut down the serverif (server instanceof Lifecycle) {try {try {// Remove the ShutdownHook first so that server.stop() // doesn't get invoked twiceRuntime.getRuntime().removeShutdownHook(shutdownHook);} catch (Throwable t) {// This will fail on JDK 1.2. Ignoring, as Tomcat can run// fine without the shutdown hook.}((Lifecycle) server).stop();} catch (LifecycleException e) {System.out.println("Catalina.stop: " + e);e.printStackTrace(System.out);if (e.getThrowable() != null) {System.out.println("----- Root Cause -----");e.getThrowable().printStackTrace(System.out);}}}}
對以上代碼的分析(Analysis): step1)該方法會創建一個Digester實例來解析server.xml(tomcat配置文件);在解析server.xml文件之前,該方法會調用 Digester.push()方法,傳入當前的Catalina對象,這樣,Catalina對象就成了Digester對象的內部棧中的第一個對象; step2)解析server.xml文件后,會使變量Server引用一個Server對象,默認是 org.apache.catalina.core.StandardServer類型的對象; step3)然后,start()方法會調用Server.initialize()方法 和 start()方法; step4)接著,Catalina.start()方法會調用server對象的await()方法,Server對象會使用一個專用的線程來等待關閉命令;await()方法會一直等待直到接收到正確的關閉命令; step5)當await()方法返回時,Catalina.start()方法會調用Server.stop()方法,從而關閉Server對象和其它的組件; Attention) A1)此外,start()方法還會利用關閉鉤子,確保用戶突然退出應用程序時會執行Server.stop()方法; A2)start()方法會調用了createStartDigester 方法創建Digester對象,createStartDigester()方法的源碼如下: protected Digester createStartDigester() {// Initialize the digesterDigester digester = new Digester();digester.setClassLoader(StandardServer.class.getClassLoader());if (debug)digester.setDebug(999);digester.setValidating(false);// Configure the actions we will be usingdigester.addObjectCreate("Server","org.apache.catalina.core.StandardServer","className");digester.addSetProperties("Server");digester.addSetNext("Server","setServer","org.apache.catalina.Server");digester.addObjectCreate("Server/GlobalNamingResources","org.apache.catalina.deploy.NamingResources");digester.addSetProperties("Server/GlobalNamingResources");digester.addSetNext("Server/GlobalNamingResources","setGlobalNamingResources","org.apache.catalina.deploy.NamingResources");digester.addObjectCreate("Server/Listener",null, // MUST be specified in the element"className");digester.addSetProperties("Server/Listener");digester.addSetNext("Server/Listener","addLifecycleListener","org.apache.catalina.LifecycleListener");digester.addObjectCreate("Server/Service","org.apache.catalina.core.StandardService","className");digester.addSetProperties("Server/Service");digester.addSetNext("Server/Service","addService","org.apache.catalina.Service");digester.addObjectCreate("Server/Service/Listener",null, // MUST be specified in the element"className");digester.addSetProperties("Server/Service/Listener");digester.addSetNext("Server/Service/Listener","addLifecycleListener","org.apache.catalina.LifecycleListener");digester.addObjectCreate("Server/Service/Connector","org.apache.catalina.connector.http.HttpConnector","className");digester.addSetProperties("Server/Service/Connector");digester.addSetNext("Server/Service/Connector","addConnector","org.apache.catalina.Connector");digester.addObjectCreate("Server/Service/Connector/Factory","org.apache.catalina.net.DefaultServerSocketFactory","className");digester.addSetProperties("Server/Service/Connector/Factory");digester.addSetNext("Server/Service/Connector/Factory","setFactory","org.apache.catalina.net.ServerSocketFactory");digester.addObjectCreate("Server/Service/Connector/Listener",null, // MUST be specified in the element"className");digester.addSetProperties("Server/Service/Connector/Listener");digester.addSetNext("Server/Service/Connector/Listener","addLifecycleListener","org.apache.catalina.LifecycleListener");// Add RuleSets for nested elementsdigester.addRuleSet(new NamingRuleSet("Server/GlobalNamingResources/"));digester.addRuleSet(new EngineRuleSet("Server/Service/"));digester.addRuleSet(new HostRuleSet("Server/Service/Engine/"));digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Default"));digester.addRuleSet(new NamingRuleSet("Server/Service/Engine/DefaultContext/"));digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Host/Default"));digester.addRuleSet(new NamingRuleSet("Server/Service/Engine/Host/DefaultContext/"));digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Host/"));digester.addRuleSet(new NamingRuleSet("Server/Service/Engine/Host/Context/"));digester.addRule("Server/Service/Engine",new SetParentClassLoaderRule(digester,parentClassLoader));return (digester);} 【1.2】stop()方法 1)intro:stop()方法用來關閉Catalina和Server對象; 2)源代碼: protected void stop() { //org.apache.catalina.startup.Catalina.stop().// Create and execute our DigesterDigester digester = createStopDigester();File file = configFile();try {InputSource is =new InputSource("file://" + file.getAbsolutePath());FileInputStream fis = new FileInputStream(file);is.setByteStream(fis);digester.push(this);digester.parse(is);fis.close();} catch (Exception e) {System.out.println("Catalina.stop: " + e);e.printStackTrace(System.out);System.exit(1);}// Stop the existing servertry {Socket socket = new Socket("127.0.0.1", server.getPort());OutputStream stream = socket.getOutputStream();String shutdown = server.getShutdown();for (int i = 0; i < shutdown.length(); i++)stream.write(shutdown.charAt(i));stream.flush();stream.close();socket.close();} catch (IOException e) {System.out.println("Catalina.stop: " + e);e.printStackTrace(System.out);System.exit(1);}} protected Digester createStopDigester() {// Initialize the digesterDigester digester = new Digester();if (debug)digester.setDebug(999);// Configure the rules we need for shutting downdigester.addObjectCreate("Server","org.apache.catalina.core.StandardServer","className");digester.addSetProperties("Server");digester.addSetNext("Server","setServer","org.apache.catalina.Server");return (digester); } Attention) A1)stop()方法:調用createStopDigester()方法來創建一個 Digester實例,并調用該實例的push()方法,并將當前Catalina對象壓入到 Digester對象的內部棧中,使用Digester對象解析tomcat 的配置文件; A2)然后,stop()方法會向正在運行的Server對象發送關閉命令,以關閉Server對象;
【1.3】啟動Digester對象 1)intro:Catalina.createStartDigester()方法創建了一個 Digester實例,然后為其添加規則,以解析server.xml文件;server.xml文件用來配置 tomcat,位于 ?%CATALINA_HOME%/conf目錄下。添加到Digester對象中的規則是理解tomcat配置的關鍵;(不能再干貨——添加到Digester對象中的關澤是理解tomcat配置的關鍵) 2)org.apache.catalina.startup.Catalina.createStartDigester()的源代碼如上所示: 因為該方法在start()方法中調用,我們在分析start方法的時候,已經分析過了;
對createStartDigester方法源代碼的分析(Analysis): step1)該方法會創建org.apache.commons.digester.Digestser類的實例,并為其添加規則(rules); step2)前3條規則用于解析 server.xml 文件的server元素。下面是為 server 模式添加的規則(因為server元素是跟元素,故又稱為模式): // Configure the actions we will be usingdigester.addObjectCreate("Server","org.apache.catalina.core.StandardServer","className");digester.addSetProperties("Server");digester.addSetNext("Server","setServer","org.apache.catalina.Server"); rule1)第1條規則表明:在遇到server元素時,Digester要創建 StandardServer 類的一個實例; rule2)第2條規則表明:要對 Server對象的指定屬性名設置同名的屬性值; rule3)第3條規則表明:將Server對象壓入到 Digester對象的內部棧中,并與棧中的下一個對象相關聯。 3)下一個對象是Catalina實例,調用其setServer()方法與 Server對象相關聯。那Catalina實例是如何防盜Digester 對象的內部棧中的呢? 在start()方法的開始部分,在解析 server.xml文件之前,會調用 Digester.push()方法將Catalina對象壓入棧: digester.push(this); 【1.4】 關閉Digetster對象 1)intro to createStopDigester()方法:該方法會返回一個 Digester對象來關閉 Server對象; protected Digester createStopDigester() { //org.apache.catalina.startup.createStopDigester().// Initialize the digesterDigester digester = new Digester();if (debug)digester.setDebug(999);// Configure the rules we need for shutting downdigester.addObjectCreate("Server","org.apache.catalina.core.StandardServer","className");digester.addSetProperties("Server");digester.addSetNext("Server","setServer","org.apache.catalina.Server");return (digester);} Attention)與啟動Digester對象不同,關閉Digester對象只對XML 文檔的根元素感興趣;
【2】 Bootstrap類(org.apache.catalina.startup.Bootstrap) 1)intro:該類提供了啟動tomcat的入口點; 2)當運行startup.bat 文件或 startup.sh 文件時,實際上是調用了該類的main()方法。main方法會創建3個類載入器,并實例化Catalina類;然后它調用Catalina.process()方法; 3)Bootstrap類的定義如下: public final class Bootstrap { private static int debug = 0; public static void main(String args[]) {// Set the debug flag appropriatelyfor (int i = 0; i < args.length; i++) {if ("-debug".equals(args[i]))debug = 1;}// Configure catalina.base from catalina.home if not yet setif (System.getProperty("catalina.base") == null)System.setProperty("catalina.base", getCatalinaHome());// Construct the class loaders we will needClassLoader 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);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);unpacked[0] = new File(getCatalinaHome(),"server" + File.separator + "classes");packed[0] = new File(getCatalinaHome(),"server" + File.separator + "lib");catalinaLoader =ClassLoaderFactory.createClassLoader(unpacked, packed,commonLoader);unpacked[0] = new File(getCatalinaBase(),"shared" + File.separator + "classes");packed[0] = new File(getCatalinaBase(),"shared" + File.separator + "lib");sharedLoader =ClassLoaderFactory.createClassLoader(unpacked, packed,commonLoader);} catch (Throwable t) {log("Class loader creation threw exception", t);System.exit(1);}Thread.currentThread().setContextClassLoader(catalinaLoader);// Load our startup class and call its process() methodtry {SecurityClassLoad.securityClassLoad(catalinaLoader);// Instantiate a startup class instanceif (debug >= 1)log("Loading startup class");Class startupClass =catalinaLoader.loadClass("org.apache.catalina.startup.Catalina"); //highlight line.Object startupInstance = startupClass.newInstance();// Set the shared extensions class loaderif (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);// Call the process() method //highlight line.if (debug >= 1)log("Calling startup class process() method");methodName = "process"; //highlight line.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);}} private static String getCatalinaHome() {return System.getProperty("catalina.home",System.getProperty("user.dir"));} private static String getCatalinaBase() {return System.getProperty("catalina.base", getCatalinaHome());} private static void log(String message) {System.out.print("Bootstrap: ");System.out.println(message);} private static void log(String message, Throwable exception) {log(message);exception.printStackTrace(System.out);} } 對以上代碼的分析(Analysis): A1)Bootstrap類有4個靜態方法:兩個log()方法,getCatalinaHome()方法 和 getCatalinaBase()方法; A2)getCatalinaHome()方法:其基本含義是,如果先前沒有設置過catalina.home 屬性的值,它就返回 user.dir屬性的值; A3)?getCatalinaBase()方法:基本含義是,如果catalina.base屬性的值為空,則返回 catalina.home屬性的值; A4)Bootstrap.main()方法中還會為不同目的而創建3個類載入器;使用多個類載入器的目的是為了防止應用程序中的類(包括servlet類和web 應用程序中的其他輔助類)使用 WEB-INF/classes目錄 和 WEB-INF/lib 目錄之外的類。部署到 %CATALINA_HOME%/common/lib 目錄下的那個 JAR 文件的類文件是可以使用的;(干貨——Bootstrap.main()方法中還會為不同目的而創建3個類載入器) 4)對3個類載入器進行詳細說明 4.0)三個類載入器的定義如下: // Construct the class loaders we will need ClassLoader commonLoader = null; ClassLoader catalinaLoader = null; ClassLoader sharedLoader = null; Attention)對于每個類載入器都會指定一條可以訪問的路徑; 4.1)commonLoader類載入器可以載入: %CATALINA_HOME%/common/classes 目錄, %CATALINA_HOME%/common/endorsed 目錄 和 %CATALINA_HOME%/common/lib 目錄下的java類; try {File unpacked[] = new File[1];File packed[] = new File[1];File packed2[] = new File[2];ClassLoaderFactory.setDebug(debug);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); 4.2)catalinaLoader類加載器負責載入運行 Catalina servlet 容器所需要的類。它可以載入: %CATALINA_HOME%/server/classes 目錄,?%CATALINA_HOME%/server/lib 目錄, 以及commonLoader 類載入器可以訪問的所有目錄中的java類; unpacked[0] = new File(getCatalinaHome(),"server" + File.separator + "classes");packed[0] = new File(getCatalinaHome(),"server" + File.separator + "lib");catalinaLoader =ClassLoaderFactory.createClassLoader(unpacked, packed,commonLoader); 4.3)sharedLoader類可以載入: %CATALINA_HOME%/shared/classes 目錄 和?%CATALINA_HOME%/share/lib?目錄以及commonLoader 類載入器可以訪問的所有目錄中的java類; unpacked[0] = new File(getCatalinaBase(),"shared" + File.separator + "classes");packed[0] = new File(getCatalinaBase(),"shared" + File.separator + "lib");sharedLoader =ClassLoaderFactory.createClassLoader(unpacked, packed,commonLoader);} catch (Throwable t) {log("Class loader creation threw exception", t);System.exit(1);} public static ClassLoader createClassLoader(File unpacked[],File packed[],ClassLoader parent)throws Exception { //org.apache.catalina.startup.ClassLoaderFactory.createClassLoader().if (debug >= 1)log("Creating new class loader");// Construct the "class path" for this class loaderArrayList list = new ArrayList();// Add unpacked directoriesif (unpacked != null) {for (int i = 0; i < unpacked.length; i++) {File file = unpacked[i];if (!file.isDirectory() || !file.exists() || !file.canRead())continue;if (debug >= 1)log(" Including directory " + file.getAbsolutePath());URL url = new URL("file", null,file.getCanonicalPath() + File.separator);list.add(url.toString());}}// Add packed directory JAR filesif (packed != null) {for (int i = 0; i < packed.length; i++) {File directory = packed[i];if (!directory.isDirectory() || !directory.exists() ||!directory.canRead())continue;String filenames[] = directory.list();for (int j = 0; j < filenames.length; j++) {String filename = filenames[j].toLowerCase();if (!filename.endsWith(".jar"))continue;File file = new File(directory, filenames[j]);if (debug >= 1)log(" Including jar file " + file.getAbsolutePath());URL url = new URL("file", null,file.getCanonicalPath());list.add(url.toString());}}}// Construct the class loader itselfString array[] = (String[]) list.toArray(new String[list.size()]);StandardClassLoader classLoader = null;if (parent == null)classLoader = new StandardClassLoader(array);elseclassLoader = new StandardClassLoader(array, parent);classLoader.setDelegate(true);return (classLoader);}
Attention) A1)在tomcat中,每個 web 應用程序中與 Context容器相關聯的每個類載入器的父類載入器都是sharedLoader 類載入器; A2)sharedLoader類載入器并不能訪問 Catalina的內部類,或 CLASSPATH 環境變量指定的類路徑中的類; 5)在創建了3個類載入器之后,main()方法會載入Catalina類并創建它的一個實例,然后再將其賦值給 startupInstance 變量: Class startupClass =catalinaLoader.loadClass("org.apache.catalina.startup.Catalina");Object startupInstance = startupClass.newInstance(); 6)然后,它調用setParentClassLoader()方法,并將 sharedLoader類載入器作為參數傳入: // Set the shared extensions class loaderif (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); 7)最后,main()方法會調用 Catalina.process()方法;(for spec info of Catalina.process(), please refer to the supplement of chapter [1]) // Call the process() methodif (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);
【3】在Windows 平臺上運行tomcat 1)可以調用 startup.bat或shutdown.bat?批處理文件來 啟動或關閉 tomcat;
【3.1】如何編寫批處理文件 Attention) A1)首先,批處理文件的后綴名必須是 “.bat”; A2)DOS 目錄及環境變量是區分大小寫的; 0)對批處理命令進行intro(commands): c1)rem: 該命令用于注釋。解釋器將不會執行以rem 命令開始的行; c2)pause:該命令用于暫停正在執行的批處理文件,并提示用戶按某個鍵,然后程序會繼續運行; c3)echo:該命令用于在dos 控制臺上顯示一段文本。例如,下面的命令將在控制臺上輸出“hello world”,然后暫停程序。之所以暫停程序是為了能夠使控制臺將輸出的文本顯示出來; echo hello world pause c3.1)如果想要顯示環境變量的值,需要在其的前后添加 %%;如,下面的目錄將輸出變量myVar的值: echo %myVar% c3.2)如果想要輸出操作系統的名字,可以使用如下的命令: echo %OS% c4)echo off:使用echo off 命令可以防止將批處理文件中的具體命令輸出,而只會輸出執行結果。但是,“echo off”命令本身還是會顯示出來。如果想要將 “echo off”也隱藏起來,需要使用 @echo off 命令; c5)@echo off:該命令與 echo off 命令類似,但是他會連 echo off 命令也隱藏起來; c6)set:用來設置用戶定義或命名的環境變量。在批處理文件中設置的環境變量是臨時存儲在內存中的,在批處理文件執行完成后就會銷毀; 看個荔枝)下面的set命令創建了一個名為 “usernmae”的環境變量,其值為“tang”,并輸出到console:
set username=tang echo %username% pause Attention)為了獲取變量的值,需要在變量前后添加“%”符號。如 “echo %username%”在字符串中就可以取到 username的值; c7)label:使用冒號設置一個標簽。然后可以將標簽傳遞給goto命令,這樣程序就會跳轉到標簽指定的位置。下面的語句定義了一個end的標簽:":end"; c8)goto:goto命令強制批處理文件跳轉到指定標簽所在的位置繼續執行 看個荔枝) echo start goto end echo i am a student; :end echo end pause
對以上腳本的分析(Analysis):在第1行輸出start后,批處理文件會執行 goto命令,跳轉到end標簽處; c9)if:if用來測試條件測試,有3種用法(func):(干貨——if命令用來測試條件測試,有3種用法) if variable==value nextCommand func1)測試變量的值; set myVar=3 if %myVar%==3 echo Correct func2)測試文件是否存在; if exist c:\temp\myFile.txt goto start; func3)測試錯誤值; set myVar=3 if not %myVar%==3 echo Correct
c10)not:not關鍵字用來對一條語句取反; c11)exist:當測試文件是否存在時,會使用到 if 和 exist命令; c12)接收參數:可以給批處理文件傳遞參數,并使用%1 引用第1個參數,%2 引用第2個參數,以此類推; c12.1)echo %1:將在console 輸出 第1個參數的值;(如果批處理文件的名字是 test.bat,并使用 “test hello” 命令來調用它,那么將會在console中輸出 “hello”); 看個荔枝)下面的文件會對第1個參數進行檢查。如果是start,輸出“start”;如果是stop,輸出stop;否則,輸出invalid; echo off if %1==start goto start if %1==stop goto stop go invalid :start echo start go end :stop echo stop goto end :invalid echo invalide :end
Attention)若要檢查運行批處理文件時,是否帶有參數,可以將 %1 與 空字符串進行比較。如,對于下面的批處理文件,如果運行時沒有使用參數,就會在控制臺上輸出“no parameter”; if "%1"=="" echo no parameter orif ""%1""=="""" echo no parameter c13)shift:shift命令用來將參數向后移動一位,即將%2的值復制給%1,%3的值復制給%2,以此類推;例如,下面的代碼使用一條shift命令: echo off shift echo %1 echo %2 如果在運行批處理文件時,附加了3個參數a,b和c,那么上面的命令會有如下輸出: b c 移動之后,要使用 %0 來應用第1個參數,而現在最后一個參數已經失效了; c14)call:該命令用來調用另一條命令; c15)setLocal:在批處理文件中使用 setLocal對環境變量的修改只在當前批處理腳本中有效。當遇到endLocal 命令后,在批處理文件的末尾修改的環境變量的值會恢復成原來的值; c16)start:打開一個新的Windows控制臺,并可以為這個新的控制臺指定一個名字,如:?start "title" ;此外,在 title后面,還有傳入一條將要在新的控制臺中執行的目錄,如下所示: start "title" commandName;
【3.2】 catalina.bat 批處理文件 1)catalina.bat 批處理文件用來啟動或關閉tomcat。另外兩個文件(startup.bat 和 shutdown.bat)提供了更簡單地啟動和關閉tomcat的方法。實際上,startup.bat 和 shutdown.bat 都會調用catalina.bar 文件,并傳入相應的參數; 2)在%CATALINA_HOME%/bin 目錄下,需要以下面的語法格式調用 catalina.bar 腳本: catalina? 或會使用下面的語法 從 %CATALINA_HOME%/bin 目錄下調用該腳本: bin\catalina 3)在兩種case下,參數command 的可選值包括: c1)debug:在調試器中啟動 Catalina; c2)debug -security;在使用安全管理器的case下調試 Catalina; c3)embedded:以嵌入模式啟動Catalina; c4)jpda start:在 JPDA調試器下啟動 Catalina; c5)run:在當前窗口中啟動 Catalina; r6)run -security:在當前窗口中,通過安全管理器啟動 Catalina; r7)start:在新窗口中啟動 Catalina; r8)start -security:在新窗口中通過安全管理器啟動 Catalina; r9)stop:關閉Catalina; 看個荔枝)想在新窗口中啟動 Catalina,可以使用如下命令:catalina start;
4)catalina.bat 批處理文件的內容: ?https://github.com/pacosonTang/HowTomcatWorks/blob/master/chapter17/catalina.bat 對catalina.bat 文件的分析(Analysis):暫時省略
Supplement) Supplement1)catalina.bat 文件中,通過設置MAINCLASS==org.apache.catalina.startup.Bootstrap,然后在該bat文件末尾會運行該類(Bootstrap) set MAINCLASS=org.apache.catalina.startup.Bootstrap // line 203rem Execute Java with the applicable properties //line 307. if not "%JPDA%" == "" goto doJpda if not "%SECURITY_POLICY_FILE%" == "" goto doSecurity %_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION% goto end :doSecurity %_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Djava.security.manager -Djava.security.policy=="%SECURITY_POLICY_FILE%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION% goto end :doJpda if not "%SECURITY_POLICY_FILE%" == "" goto doSecurityJpda %_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %JPDA_OPTS% %DEBUG_OPTS% -Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION% goto end :doSecurityJpda %_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %JPDA_OPTS% %DEBUG_OPTS% -Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Djava.security.manager -Djava.security.policy=="%SECURITY_POLICY_FILE%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION% goto end // line 321Supplement2) 總結tomcat啟動steps(不能再干貨) step1)startup.bat 批處理文件會調用 catalina.bat 文件,而catalina.bat批處理會運行org.apache.catalina.startup.Bootstrap 類(main方法); step2)Bootstrap.main()方法會調用 Catalina.process()方法; public final class Bootstrap { //org.apache.catalina.startup.Bootstrapprivate static int debug = 0; public static void main(String args[]) {// Set the debug flag appropriatelyfor (int i = 0; i < args.length; i++) {if ("-debug".equals(args[i]))debug = 1;}// Configure catalina.base from catalina.home if not yet setif (System.getProperty("catalina.base") == null)System.setProperty("catalina.base", getCatalinaHome());// Construct the class loaders we will needClassLoader 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);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);unpacked[0] = new File(getCatalinaHome(),"server" + File.separator + "classes");packed[0] = new File(getCatalinaHome(),"server" + File.separator + "lib");catalinaLoader =ClassLoaderFactory.createClassLoader(unpacked, packed,commonLoader);unpacked[0] = new File(getCatalinaBase(),"shared" + File.separator + "classes");packed[0] = new File(getCatalinaBase(),"shared" + File.separator + "lib");sharedLoader =ClassLoaderFactory.createClassLoader(unpacked, packed,commonLoader);} catch (Throwable t) {log("Class loader creation threw exception", t);System.exit(1);}Thread.currentThread().setContextClassLoader(catalinaLoader);// Load our startup class and call its process() methodtry {SecurityClassLoad.securityClassLoad(catalinaLoader);// Instantiate a startup class instanceif (debug >= 1)log("Loading startup class");Class startupClass =catalinaLoader.loadClass("org.apache.catalina.startup.Catalina"); //highlight line.Object startupInstance = startupClass.newInstance(); // 創建Catalina類的實例.// Set the shared extensions class loaderif (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);// Call the process() method //highlight line.if (debug >= 1)log("Calling startup class process() method");methodName = "process"; //highlight line.paramTypes = new Class[1];paramTypes[0] = args.getClass();paramValues = new Object[1];paramValues[0] = args;method =startupInstance.getClass().getMethod(methodName, paramTypes); // 調用Catalina.process()方法.method.invoke(startupInstance, paramValues);} catch (Exception e) {System.out.println("Exception during startup processing");e.printStackTrace(System.out);System.exit(2);}} private static String getCatalinaHome() {return System.getProperty("catalina.home",System.getProperty("user.dir"));} private static String getCatalinaBase() {return System.getProperty("catalina.base", getCatalinaHome());} private static void log(String message) {System.out.print("Bootstrap: ");System.out.println(message);} private static void log(String message, Throwable exception) {log(message);exception.printStackTrace(System.out);} } Attention)文末會對createStateDigester()方法的調用過程進一步總結;(限于篇幅)
<?xml version='1.0' encoding='utf-8'?> <!--conf/server.xml源碼如下 --> <!--Licensed to the Apache Software Foundation (ASF) under one or morecontributor license agreements. See the NOTICE file distributed withthis work for additional information regarding copyright ownership.The ASF licenses this file to You under the Apache License, Version 2.0(the "License"); you may not use this file except in compliance withthe License. You may obtain a copy of the License athttp://www.apache.org/licenses/LICENSE-2.0Unless required by applicable law or agreed to in writing, softwaredistributed under the License is distributed on an "AS IS" BASIS,WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.See the License for the specific language governing permissions andlimitations under the License. --> <!-- Note: A "Server" is not itself a "Container", so you may notdefine subcomponents such as "Valves" at this level.Documentation at /docs/config/server.html--> <Server port="8005" shutdown="SHUTDOWN"><!-- Security listener. Documentation at /docs/config/listeners.html<Listener className="org.apache.catalina.security.SecurityListener" />--><!--APR library loader. Documentation at /docs/apr.html --><Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" /><!--Initialize Jasper prior to webapps are loaded. Documentation at /docs/jasper-howto.html --><Listener className="org.apache.catalina.core.JasperListener" /><!-- Prevent memory leaks due to use of particular java/javax APIs--><Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" /><Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" /><Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" /><!-- Global JNDI resourcesDocumentation at /docs/jndi-resources-howto.html--><GlobalNamingResources><!-- Editable user database that can also be used byUserDatabaseRealm to authenticate users--><Resource name="UserDatabase" auth="Container"type="org.apache.catalina.UserDatabase"description="User database that can be updated and saved"factory="org.apache.catalina.users.MemoryUserDatabaseFactory"pathname="conf/tomcat-users.xml" /></GlobalNamingResources><!-- A "Service" is a collection of one or more "Connectors" that sharea single "Container" Note: A "Service" is not itself a "Container",so you may not define subcomponents such as "Valves" at this level.Documentation at /docs/config/service.html--><Service name="Catalina"><!--The connectors can use a shared executor, you can define one or more named thread pools--><!--<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"maxThreads="150" minSpareThreads="4"/>--><!-- A "Connector" represents an endpoint by which requests are receivedand responses are returned. Documentation at :Java HTTP Connector: /docs/config/http.html (blocking & non-blocking)Java AJP Connector: /docs/config/ajp.htmlAPR (HTTP/AJP) Connector: /docs/apr.htmlDefine a non-SSL HTTP/1.1 Connector on port 8080--><Connector port="8888" protocol="HTTP/1.1"connectionTimeout="20000"redirectPort="8443" /><!-- A "Connector" using the shared thread pool--><!--<Connector executor="tomcatThreadPool"port="8080" protocol="HTTP/1.1"connectionTimeout="20000"redirectPort="8443" />--><!-- Define a SSL HTTP/1.1 Connector on port 8443This connector uses the JSSE configuration, when using APR, theconnector should be using the OpenSSL style configurationdescribed in the APR documentation --><!--<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"maxThreads="150" scheme="https" secure="true"clientAuth="false" sslProtocol="TLS" />--><!-- Define an AJP 1.3 Connector on port 8009 --><Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /><!-- An Engine represents the entry point (within Catalina) that processesevery request. The Engine implementation for Tomcat stand aloneanalyzes the HTTP headers included with the request, and passes themon to the appropriate Host (virtual host).Documentation at /docs/config/engine.html --><!-- You should set jvmRoute to support load-balancing via AJP ie :<Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm1">--><Engine name="Catalina" defaultHost="localhost"><!--For clustering, please take a look at documentation at:/docs/cluster-howto.html (simple how to)/docs/config/cluster.html (reference documentation) --><!--<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>--><!-- Use the LockOutRealm to prevent attempts to guess user passwordsvia a brute-force attack --><Realm className="org.apache.catalina.realm.LockOutRealm"><!-- This Realm uses the UserDatabase configured in the global JNDIresources under the key "UserDatabase". Any editsthat are performed against this UserDatabase are immediatelyavailable for use by the Realm. --><Realm className="org.apache.catalina.realm.UserDatabaseRealm"resourceName="UserDatabase"/></Realm><Host name="localhost" appBase="webapps"unpackWARs="true" autoDeploy="true"><!-- SingleSignOn valve, share authentication between web applicationsDocumentation at: /docs/config/valve.html --><!--<Valve className="org.apache.catalina.authenticator.SingleSignOn" />--><!-- Access log processes all example.Documentation at: /docs/config/valve.htmlNote: The pattern used is equivalent to using pattern="common" --><Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"prefix="localhost_access_log." suffix=".txt"pattern="%h %l %u %t "%r" %s %b" /></Host></Engine></Service> </Server> 對以上server.xml代碼的分析(Analysis): A1)創建一個服務器組件; A1.1)服務器組件里面注入多個監聽器,資源(GlobalNamingResources) A1.2)創建一個服務組件; A1.2.1)創建兩個Connector; A1.2.2)創建一個Engine,Engine中注入兩個領域對象(Realm);還注入了一個Host容器;和一個閥; Attention) A1)服務器組件和服務組件,參見 tomcat(14)服務器組件和服務組件; A2)Digester用于將XML 文檔中的元素轉換成 java 對象,參見?tomcat(15)Digester庫
Conclusion)(不能再干貨——tomcat的啟動調用過程review)
C1)自此,tomcat的啟動調用過程我們已經分析完畢,再review 一下: startup.bat -> catalina.bat -> Bootstrap.main() -> Catalina.process() -> ?createStartDigester() ->configFile() ;
C2)啟動createStartDigester方法會創建Digester類,用于將server.xml 中的元素轉換為java對象;而configFile方法就是用于設定 將要解析的xml的文件路徑的.
【3.3】在Windows 平臺上啟動tomcat(startup.bat 文件調用catalina.bat 文件時,會傳入參數 start) https://github.com/pacosonTang/HowTomcatWorks/blob/master/chapter17/startup.bat
【3.4】在Windows 平臺上關閉tomcat(shutdown.bat 文件調用 catalina.bat文件時,傳入參數 stop) https://github.com/pacosonTang/HowTomcatWorks/blob/master/chapter17/shutdown.bat
【4】在Linux平臺上啟動Tomcat 1)在linux平臺上,tomcat使用shell 腳本來啟動和關閉。shell腳本的后綴名可以是 “.sh”,位于 $CATALINA_HOME/bin 目錄下; 2)intro:本章節將intro 4 個腳本:catalina.sh, statup.sh, shutdown.sh, setclasspath.sh;
【4.1】如何編寫UNIX/Linux Shell腳本 1)intro:shell腳本是由解釋器逐行執行的,shell 腳本的擴展名可有可無,但最常用的擴展名是 .sh; 2)下面簡單介紹下 shell 命令(command): c1)注釋:shell腳本使用 # 符號來表示注釋內容; c2)clear:使用該命令來清空屏幕; c3)exit:該命令可以用來退出當前shell 腳本的執行;一般case下,exit后面都會附加一個退出狀態,其中0 表示shell腳本正常執行完成,非0值表示shell異常退出;如果因為程序運行中的某種異常而想退出,使用如下命令:exit 1;(干貨——exit后面都會附加一個退出狀態,其中0 表示shell腳本正常執行完成,非0值表示shell異常退出) c4)echo:該命令可以向屏幕輸出一個字符串:echo hello world; c5)調用函數:可以使用句點(.)來調用一個函數,或執行另一個shell 腳本; c6)系統變量與用于自定義變量:變量名必須以字母,數字或下劃線開頭,使用等號就可以定義一個變量;如下面的命令定義了一個名為 myVar 的變量,其值為 Tootsie:myVar=Toosie; Attention) A1)等號的前后一定不能有空格。此外,shell 腳本對變量名是區分大小寫的 ; A2)若想定義一個值為NULL的變量,可使用空字符串為其賦值,或在等號右邊留空即可: myVar= myVar="" A3)若想要獲取變量的值,需要在變量前面加上美元符號($):echo $myVar A4)Unix/Linux 提供了一些系統變量供用戶使用;如,變量HOME 保存了當前用戶的主目錄,變量PWD 保存了用戶當前所在的目錄,變量PATH 保存了將會在哪些地方查找要執行的命令等; c7)expr: 可以使用該命令來計算一個表達式的值。表達式必須以反引號引用;如下面的shell 腳本計算一個數學表達式: sum=`expr 100+200` echo $sum c7.1)腳本:echo `expr 200+300` 會輸出500; c7.2)特殊表達式`uname`會得到操作系統的名稱:echo `uname` 會輸出操作系統名稱(Linux或Unix); c7.3)特殊表達式 `dirname filePath` 會返回指定文件所在的目錄。如,命令 `dirname /home/user1/test.sh` 會返回“home/user1”; c8)訪問參數:如同向函數中傳入參數一樣,也可以向shell腳本傳入參數,并使用 $1 來引用第1個參數,$2引用第2個參數,以此類推;$# 會返回參數的格式,$@會返回所有的參數; c9)shift:這條命令會將參數向后移動一位,$1的值改為 $2, $2的值改為$3, 以此類推; c10)if...then...[else...] fi:if 語句用來測試條件,并執行相應的命令列表。它的語法格式如下: if condition thenlist of commands [elselist of commands ] fi Attention)也可以使用 “elif”來代替“else if”; 看個荔枝)如下面的shell腳本,若傳入的第1個參數是 “start”,運行下面的腳本,會輸出“start”;如果傳入的第1個參數是 “stop”,則輸出“stop”;
if [ "$1" = "start" ]; thenecho start fi if [ "$1" = "end" ]; thenecho end fi Attention)
A1)判斷條件在 “[” 后面必須有一個空格, 在“]”前面也必須有一個空格; A2)將 $1 用雙引號引起來可以防止解釋器在發現調用腳本時沒有使用參數而拋出異常; A3)$0:表示的是用來調用該腳本的命令。如,使用下面的命令來調用一個名為 test.sh 的腳本:./test.sh; 那么,$0 返回 “./test.sh”;下面是一些用來進行條件判斷的測試選項: -f file:當存在文件file時,為true; -r file:當文件file可讀時,為true; -z string:如果string 是空字符串,為 true; -n string:如果string 不為空字符串,為true; string1 = string2:如果string1 等于string2,為true; string1 != string2:如果string1 不等于 string2,為true; c11)for循環:使用for循環來重復執行一些命令: for {var} in {list} dolist of commands done 看個荔枝)
for i in 1 2 3 doecho i=$i done output: i1 i2 i3 c12)while循環: while [condition] dolist of commands done
看個荔枝)
n=1 while [$n -lt 3] doecho i $n done output: i1 i2 Attention)其中 [$n -lt 3];中 -lt 的意思是小于3,(lt == less than) c13)case:case結構表示可以在程序中執行一些選擇過程。其語法格式如下所示: case $variable-name in pattern1)list of commands;; pattern2)list of commands;; *)list of commands;; esac Attention)“;;”表示命令列表執行完成,如果上面的模式都不匹配時,“*)”表示所要執行的命令; 看個荔枝) case "`uname`" inCYGWIN*)echo cygwin;;OS400*)echo os400;;LINUX*)echo linux;;*)echo os not recognized;; esac c14)輸出重定向(review):使用 “>”將輸出重定向到一個文件;(echo hello > myFile.txt);這會創建一個 myFile.txt的文件,并將 hello 寫入到其中,不會向屏幕上輸出文字; Supplement) S1)"1>&2":會把標準輸出上的錯誤消息重定向到標準錯誤中; S1)"2>&1":會把標準錯誤中的信息重新向到 標準輸出中;
c15)條件執行:可以使用命令或條件來決定是否執行另一條命令。在這種 case下, 可以使用 && 或 || ,如下所示: c15.1)command1 && command2:如果command1返回的退出狀態是0,那么會執行command2;(0表true,非0表false) c15.2)command1 || command2:如果command1返回的退出狀態是非0,那么會執行command2;(0表true,非0表false) c15.3)command1 && command2 || command3:如果command1返回的退出狀態是非0,那么會執行command2;否則,執行command3;(0表true,非0表false);
【4.2】catalina.sh 腳本 1)intro: 該文件用來在 UNIX/Linux 平臺上啟動或關閉tomcat。若要啟動tomcat,需要將 start作為第1個參數傳遞給 catalina.sh 腳本。若要關閉 tomcat,需要將stop 作為第1個參數傳遞給 catalina.sh腳本。下面是有效的 參數列表(parameters): p1)debug:在調試器中啟動catalina;(在OS400系統上不可用) p2)debug -security:通過安全管理器調試catalina;(在OS400系統上不可用) p3)embedded:以嵌入模式啟動 Catalina; p4)jpda start:在JPDA 調試器下啟動 Catalina; p5)run:在當前窗口中啟動 Catalina; p6)run -security:在安全管理器下,使用當前窗口啟動 catalina; p7)start:使用一個新窗口啟動 catalina; p8)start -security:在安全管理器下,使用一個新窗口啟動 catalina; p9)stop:關閉 catalina; 2)catalina.sh 的源代碼,參見: ?https://github.com/pacosonTang/HowTomcatWorks/blob/master/chapter17/catalina.sh
【4.3】在 unix/linux 平臺上啟動 tomcat 1)使用 startup.sh 腳本可以方便地啟動 tomcat。startup.sh 腳本會設置正確的環境變量,然后調用 catalina.sh腳本,并傳入參數 start: ?https://github.com/pacosonTang/HowTomcatWorks/blob/master/chapter17/startup.sh
【4.4】在 unix/linux 平臺上關閉 tomcat 1)使用 shutdown.sh 腳本可以方便地啟動 tomcat。shutdown.sh 腳本會設置正確的環境變量,然后調用 catalina.sh腳本,并傳入參數 stop: ?https://github.com/pacosonTang/HowTomcatWorks/blob/master/chapter17/shutdown.sh
------------------------------------------------------------------------------------------------------ Supplement)文末繼續對 Catatalina.createStateDigester()方法的調用過程進一步總結 protected Digester createStartDigester() { //org.apache.catalina.startup.Catalina.createStartDigester().// Initialize the digesterDigester digester = new Digester();digester.setClassLoader(StandardServer.class.getClassLoader());if (debug)digester.setDebug(999);digester.setValidating(false);// Configure the actions we will be usingdigester.addObjectCreate("Server","org.apache.catalina.core.StandardServer","className");digester.addSetProperties("Server");digester.addSetNext("Server","setServer","org.apache.catalina.Server");digester.addObjectCreate("Server/GlobalNamingResources","org.apache.catalina.deploy.NamingResources");digester.addSetProperties("Server/GlobalNamingResources");digester.addSetNext("Server/GlobalNamingResources","setGlobalNamingResources","org.apache.catalina.deploy.NamingResources");digester.addObjectCreate("Server/Listener",null, // MUST be specified in the element"className");digester.addSetProperties("Server/Listener");digester.addSetNext("Server/Listener","addLifecycleListener","org.apache.catalina.LifecycleListener");digester.addObjectCreate("Server/Service","org.apache.catalina.core.StandardService","className");digester.addSetProperties("Server/Service");digester.addSetNext("Server/Service","addService","org.apache.catalina.Service");digester.addObjectCreate("Server/Service/Listener",null, // MUST be specified in the element"className");digester.addSetProperties("Server/Service/Listener");digester.addSetNext("Server/Service/Listener","addLifecycleListener","org.apache.catalina.LifecycleListener");digester.addObjectCreate("Server/Service/Connector","org.apache.catalina.connector.http.HttpConnector","className");digester.addSetProperties("Server/Service/Connector");digester.addSetNext("Server/Service/Connector","addConnector","org.apache.catalina.Connector");digester.addObjectCreate("Server/Service/Connector/Factory","org.apache.catalina.net.DefaultServerSocketFactory","className");digester.addSetProperties("Server/Service/Connector/Factory");digester.addSetNext("Server/Service/Connector/Factory","setFactory","org.apache.catalina.net.ServerSocketFactory");digester.addObjectCreate("Server/Service/Connector/Listener",null, // MUST be specified in the element"className");digester.addSetProperties("Server/Service/Connector/Listener");digester.addSetNext("Server/Service/Connector/Listener","addLifecycleListener","org.apache.catalina.LifecycleListener");// Add RuleSets for nested elementsdigester.addRuleSet(new NamingRuleSet("Server/GlobalNamingResources/"));digester.addRuleSet(new EngineRuleSet("Server/Service/")); //highlight line.digester.addRuleSet(new HostRuleSet("Server/Service/Engine/")); //highlight line.digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Default")); //highlight line.digester.addRuleSet(new NamingRuleSet("Server/Service/Engine/DefaultContext/"));digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Host/Default"));digester.addRuleSet(new NamingRuleSet("Server/Service/Engine/Host/DefaultContext/"));digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Host/"));digester.addRuleSet(new NamingRuleSet("Server/Service/Engine/Host/Context/"));digester.addRule("Server/Service/Engine",new SetParentClassLoaderRule(digester,parentClassLoader));return (digester);} public void addRuleInstances(Digester digester) { //org.apache.catalina.startup.EngineRuleSet.addRuleInstances().digester.addObjectCreate(prefix + "Engine","org.apache.catalina.core.StandardEngine","className");digester.addSetProperties(prefix + "Engine");digester.addRule(prefix + "Engine",new LifecycleListenerRule(digester,"org.apache.catalina.startup.EngineConfig","engineConfigClass"));digester.addSetNext(prefix + "Engine","setContainer","org.apache.catalina.Container");digester.addObjectCreate(prefix + "Engine/Listener",null, // MUST be specified in the element"className");digester.addSetProperties(prefix + "Engine/Listener");digester.addSetNext(prefix + "Engine/Listener","addLifecycleListener","org.apache.catalina.LifecycleListener");digester.addObjectCreate(prefix + "Engine/Logger",null, // MUST be specified in the element"className");digester.addSetProperties(prefix + "Engine/Logger");digester.addSetNext(prefix + "Engine/Logger","setLogger","org.apache.catalina.Logger");digester.addObjectCreate(prefix + "Engine/Realm",null, // MUST be specified in the element"className");digester.addSetProperties(prefix + "Engine/Realm");digester.addSetNext(prefix + "Engine/Realm","setRealm","org.apache.catalina.Realm");digester.addObjectCreate(prefix + "Engine/Valve",null, // MUST be specified in the element"className");digester.addSetProperties(prefix + "Engine/Valve");digester.addSetNext(prefix + "Engine/Valve","addValve","org.apache.catalina.Valve");}public void addRuleInstances(Digester digester) { //org.apache.catalina.startup.HostRuleSet.addRuleInstances().digester.addObjectCreate(prefix + "Host","org.apache.catalina.core.StandardHost","className");digester.addSetProperties(prefix + "Host");digester.addRule(prefix + "Host",new CopyParentClassLoaderRule(digester));digester.addRule(prefix + "Host",new LifecycleListenerRule(digester,"org.apache.catalina.startup.HostConfig","hostConfigClass"));digester.addSetNext(prefix + "Host","addChild","org.apache.catalina.Container");digester.addCallMethod(prefix + "Host/Alias","addAlias", 0);digester.addObjectCreate(prefix + "Host/Cluster",null, // MUST be specified in the element"className");digester.addSetProperties(prefix + "Host/Cluster");digester.addSetNext(prefix + "Host/Cluster","addCluster","org.apache.catalina.Cluster");digester.addObjectCreate(prefix + "Host/Listener",null, // MUST be specified in the element"className");digester.addSetProperties(prefix + "Host/Listener");digester.addSetNext(prefix + "Host/Listener","addLifecycleListener","org.apache.catalina.LifecycleListener");digester.addObjectCreate(prefix + "Host/Logger",null, // MUST be specified in the element"className");digester.addSetProperties(prefix + "Host/Logger");digester.addSetNext(prefix + "Host/Logger","setLogger","org.apache.catalina.Logger");digester.addObjectCreate(prefix + "Host/Realm",null, // MUST be specified in the element"className");digester.addSetProperties(prefix + "Host/Realm");digester.addSetNext(prefix + "Host/Realm","setRealm","org.apache.catalina.Realm");digester.addObjectCreate(prefix + "Host/Valve",null, // MUST be specified in the element"className");digester.addSetProperties(prefix + "Host/Valve");digester.addSetNext(prefix + "Host/Valve","addValve","org.apache.catalina.Valve");}public void addRuleInstances(Digester digester) { //<span style="font-family:Arial, Helvetica, sans-serif;"> org.apache.catalina.ContextRuleSet.addRuleInstances().</span>if (!isDefaultContext()) {digester.addObjectCreate(prefix + "Context","org.apache.catalina.core.StandardContext","className");} else {digester.addObjectCreate(prefix + "Context","org.apache.catalina.core.StandardDefaultContext","className");}digester.addSetProperties(prefix + "Context");if (!isDefaultContext()) {digester.addRule(prefix + "Context",new CopyParentClassLoaderRule(digester));digester.addRule(prefix + "Context",new LifecycleListenerRule(digester,"org.apache.catalina.startup.ContextConfig","configClass"));digester.addSetNext(prefix + "Context","addChild","org.apache.catalina.Container");digester.addRule(prefix + "Context",new ContextValidatorRule(digester));} else {digester.addSetNext(prefix + "Context","addDefaultContext","org.apache.catalina.DefaultContext");}digester.addCallMethod(prefix + "Context/InstanceListener","addInstanceListener", 0);digester.addObjectCreate(prefix + "Context/Listener",null, // MUST be specified in the element"className");digester.addSetProperties(prefix + "Context/Listener");digester.addSetNext(prefix + "Context/Listener","addLifecycleListener","org.apache.catalina.LifecycleListener");digester.addRule(prefix + "Context/Loader",new CreateLoaderRule(digester,"org.apache.catalina.loader.WebappLoader","className"));digester.addSetProperties(prefix + "Context/Loader");digester.addSetNext(prefix + "Context/Loader","setLoader","org.apache.catalina.Loader");digester.addObjectCreate(prefix + "Context/Logger",null, // MUST be specified in the element"className");digester.addSetProperties(prefix + "Context/Logger");digester.addSetNext(prefix + "Context/Logger","setLogger","org.apache.catalina.Logger");digester.addObjectCreate(prefix + "Context/Manager","org.apache.catalina.session.StandardManager","className");digester.addSetProperties(prefix + "Context/Manager");digester.addSetNext(prefix + "Context/Manager","setManager","org.apache.catalina.Manager");digester.addObjectCreate(prefix + "Context/Manager/Store",null, // MUST be specified in the element"className");digester.addSetProperties(prefix + "Context/Manager/Store");digester.addSetNext(prefix + "Context/Manager/Store","setStore","org.apache.catalina.Store");digester.addObjectCreate(prefix + "Context/Parameter","org.apache.catalina.deploy.ApplicationParameter");digester.addSetProperties(prefix + "Context/Parameter");digester.addSetNext(prefix + "Context/Parameter","addApplicationParameter","org.apache.catalina.deploy.ApplicationParameter");digester.addObjectCreate(prefix + "Context/Realm",null, // MUST be specified in the element"className");digester.addSetProperties(prefix + "Context/Realm");digester.addSetNext(prefix + "Context/Realm","setRealm","org.apache.catalina.Realm");digester.addObjectCreate(prefix + "Context/ResourceLink","org.apache.catalina.deploy.ContextResourceLink");digester.addSetProperties(prefix + "Context/ResourceLink");digester.addSetNext(prefix + "Context/ResourceLink","addResourceLink","org.apache.catalina.deploy.ContextResourceLink");digester.addObjectCreate(prefix + "Context/Resources","org.apache.naming.resources.FileDirContext","className");digester.addSetProperties(prefix + "Context/Resources");digester.addSetNext(prefix + "Context/Resources","setResources","javax.naming.directory.DirContext");digester.addObjectCreate(prefix + "Context/Valve",null, // MUST be specified in the element"className");digester.addSetProperties(prefix + "Context/Valve");digester.addSetNext(prefix + "Context/Valve","addValve","org.apache.catalina.Valve");digester.addCallMethod(prefix + "Context/WrapperLifecycle","addWrapperLifecycle", 0);digester.addCallMethod(prefix + "Context/WrapperListener","addWrapperListener", 0);}?對以上代碼的分析(Analysis): A1)EngineRuleSet.addRuleInstances()方法:創建Engine容器StandardEngine,Engine監聽器EngineConfig, 聲明周期監聽器?LifecycleListener, 日志Logger, 領域對象Realm, 管道閥對象?Valve; A2)HostRuleSet.addRuleInstances()方法:創建Host容器StandardHost, Host監聽器HostConfig, 集群Cluster, 生命周期監聽器LifecycleListener,?日志Logger, 領域對象Realm, 管道閥對象?Valve; A3)ContextRuleSet.addRuleInstances()方法:創建Context容器?StandardContext, Context監聽器ContextConfig, 生命周期監聽器LifecycleListener,Web加載器WebappLoader, 管理器Manager,?Store, 領域對象Realm,?ContextResourceLink, 管道閥對象Valve,
總結
以上是生活随笔為你收集整理的tomcat(17)启动tomcat的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux进程占用内存过大怎么处理(li
- 下一篇: spring(2)装配Bean