天天看點

Tomcat 學習筆記

如何建立一個簡單的Servlet

添加Servlet的jar包

<dependencies>
        <dependency>
            <groupId>Javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
        </dependency>
    </dependencies>
           

建立ServletTest.java

建立一個ServletTest.java檔案如下

package com.test;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

 
@WebServlet(urlPatterns = "/test")
public class ServletTest extends HttpServlet{

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().print("aaa");
    }
}

           

這個是Servlet3.0的寫法,可以通過注解的方式代替xml

這樣一個簡單的Servlet就建立好了。

到現在的話,直接打包的會報錯

Failed to execute goal org.apache.maven.plugins:maven-war-plugin:2.2:war (default-war) on project servlettest: Error assembling WAR: webxml attribute is required (or pre-existing WEB-INF/web.xml if executing in update mode) -> [Help 1]

因為在打war包的時候,必須有web.xml,可是我們沒有建立,在這裡使用maven-war的插件即可

<build>
        <plugins>
          <plugin>
              <groupId>org.apache.maven.plugins</groupId>
              <artifactId>maven-war-plugin</artifactId>
              <version>3.2.0</version>
          </plugin>
        </plugins>
    </build>
           

在pom.xml 中添加這段會幫我們自動添加web.xml

到這就可以執行

mvn install

指令了,然後我們把war檔案放到tomcat 的

webapps

路徑下即可;

Tomcat 學習筆記

參考位址: (https://www.ibm.com/developerworks/cn/java/j-lo-servlet30/index.html)

Tomcat 的幾種部署方式

  1. 将war包放到複制到目錄中

    $CATALINA_BASE/webapps/

    這種形式, 當Tomcat啟動時,它會自動将Web應用程式歸檔檔案擴充為其解壓縮的形式,并且會根據子目錄名稱為應用程式配置設定上下文路徑。如果用這種方式部署,後續如果向更改了程式代碼,必須重新開機才可以生效。

    這種方式也就是上面我們測試的方式。

  2. 在tomcat的server.xml中添加context元素

    第1種方式是最簡單的,也是入門的時候最常見的。

    接下來就是這種,在servet.xml中添加如下代碼

    Tomcat 學習筆記
    <Context path="/aaa" docBase="E:\webapp\servlettest\target\servlettest-1.0-SNAPSHOT">
    </Context>
               

    docBase:web應用程式的根目錄

    path: Web應用程式的上下文路徑,與每個請求URI的開頭比對,以選擇适當的Web應用程式進行處理.

    配置完,啟動tomcat 即可通路

  3. $CATALINA_BASE/conf/catalina/localhost下建立xml

    第二種方式看似簡單,省去了複制war包的過程,在server.xml中配置難免顯得雜亂,是以我們可以将context元素的内容在

    $CATALINA_BASE/conf/catalina/localhost

    下建立一個xml, 這個xml的名稱則就是上下文的路徑,如果context中也同樣配置了path ,則還是以名稱為主。
    <?xml version="1.0" encoding="UTF-8"?>	
    	<Context path="/aaa" docBase="E:\webapp\servlettest\target\servlettest-1.0-SNAPSHOT">
    			</Context>
               
    Tomcat 學習筆記
    Tomcat 學習筆記

當然 配置context元素的方式也是直接熱部署的

更多context屬性說明:http://tomcat.apache.org/tomcat-8.5-doc/config/context.html

Tomcat Maven 插件

大家有沒有感覺到,如上開發的時候,不管如何處理,貌似都很麻煩,我們必須下載下傳tomcat,還得打包部署或者配置tomcat中的xml檔案,稍微有一個地方出錯,就特别耗費時間,然而tomcat maven 就讓我們在開發的時候省了很多時間。

  1. ​ 在pom.xml添加如下:
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>com.servlet</groupId>
        <artifactId>servlettest</artifactId>
        <version>1.0-SNAPSHOT</version>
        <packaging>war</packaging>
        <dependencies>
            <dependency>
                <groupId>Javax.servlet</groupId>
                <artifactId>javax.servlet-api</artifactId>
                <version>3.1.0</version>
                <scope>provided</scope>
            </dependency>
        </dependencies>
        <build>
            <plugins>
              <plugin>
                  <groupId>org.apache.maven.plugins</groupId>
                  <artifactId>maven-war-plugin</artifactId>
                  <version>3.2.0</version>
              </plugin>
                
                <!--**** 在此位置添加tomcat 插件 **** -->
                <plugin>
                    <!--這個是配置說明位址請大家參考:http://tomcat.apache.org/maven-plugin-trunk/run-mojo-features.html-->
                    <groupId>org.apache.tomcat.maven</groupId>
                    <artifactId>tomcat7-maven-plugin</artifactId>
                    <configuration>
                         <port>8080</port>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </project>
               

    添加之後,插件就會下載下傳,稍微等下就好。

    如果是idea 的話 配置下

    tomcat7:run

    即可啟動
Tomcat 學習筆記

maven插件配置說明位址請大家參考:http://tomcat.apache.org/maven-plugin-trunk/run-mojo-features.html

maven tomcat 深入的了解

​ 看到maven tomcat 如此的友善,就對這個插件産生的濃厚的好奇心。

​ 首先我們打包下,

<plugin>
                <!--http://tomcat.apache.org/maven-plugin-trunk/run-mojo-features.html-->
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <configuration>
                     <port>8080</port>
                </configuration>
                <executions>
                    <execution>
                        <id>tomcat-run</id>
                        <goals>
                            <goal>exec-war-only</goal>
                        </goals>
                        <phase>package</phase>
                        <configuration>
                            <path>/</path>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
           

更改下pom.xml中的配置 然後打包下,然後在target檔案夾中發現了有一個jar

Tomcat 學習筆記

這個jar 是可以直接

java -jar

執行的,那麼既然的jar,他就一定有一個入口方法,我就從入口方法下手,看看這個是如何運作的。

​ 果然在MANIFEST.MF 檔案中發現了這段

Manifest-Version: 1.0

Main-Class: org.apache.tomcat.maven.runner.Tomcat7RunnerCli

很明顯,這就是他的入口。

那麼在pom.xml 添加jar的依賴,檢視下入口到底長什麼樣子。

<dependency>
            <groupId>org.apache.tomcat.maven</groupId>
            <artifactId>tomcat7-maven-plugin</artifactId>
            <version>2.2</version>
        </dependency>
           

注:maven 插件其實也是一個jar檔案而已。直接添加依賴即可;

Tomcat 學習筆記

找到main入口之後,依次發現代碼沒什麼

大概梳理了下代碼

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.apache.tomcat.maven.runner;

import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.Properties;
import java.util.Map.Entry;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.GnuParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;

public class Tomcat7RunnerCli {
    public static final String STAND_ALONE_PROPERTIES_FILENAME = "tomcat.standalone.properties";
    static Option httpPort;
    static Option httpsPort;
    static Option ajpPort;
    static Option serverXmlPath;
    static Option resetExtract;
    static Option help;
    static Option debug;
    static Option sysProps;
    static Option clientAuth;
    static Option keyAlias;
    static Option obfuscate;
    static Option httpProtocol;
    static Option extractDirectory;
    static Option loggerName;
    static Option uriEncoding;
    static Options options;

    public Tomcat7RunnerCli() {
    }

    public static void main(String[] args) throws Exception {
		// 建立解析器
        CommandLineParser parser = new GnuParser();
        CommandLine line = null;

        try {
			// 解析參數,例如:spring boot 啟動方式  java -jar demo.jar --server.port=8080   通過server.port 設定端口号   不過這裡是httpPort  
            line = parser.parse(options, args);
        } catch (ParseException var8) {
            System.err.println("Parsing failed.  Reason: " + var8.getMessage());
            HelpFormatter formatter = new HelpFormatter();
            formatter.printHelp(getCmdLineSyntax(), options);
            System.exit(1);
        }

        if (line.hasOption(help.getOpt())) {
            HelpFormatter formatter = new HelpFormatter();
            formatter.printHelp(getCmdLineSyntax(), options);
            System.exit(0);
        }

        if (line.hasOption(obfuscate.getOpt())) {
            System.out.println(PasswordUtil.obfuscate(line.getOptionValue(obfuscate.getOpt())));
            System.exit(0);
        }
		// 建立Tomcat對象
        Tomcat7Runner tomcat7Runner = new Tomcat7Runner();
        tomcat7Runner.runtimeProperties = buildStandaloneProperties();
        if (line.hasOption(serverXmlPath.getOpt())) {
            tomcat7Runner.serverXmlPath = line.getOptionValue(serverXmlPath.getOpt());
        }
		// 擷取端口号
        String port = tomcat7Runner.runtimeProperties.getProperty("httpPort");
        if (port != null) {
            tomcat7Runner.httpPort = Integer.parseInt(port);
        }
		// 擷取啟動時的端口号,啟動時設定的端口号優先
        if (line.hasOption(httpPort.getOpt())) {
            tomcat7Runner.httpPort = Integer.parseInt(line.getOptionValue(httpPort.getOpt()));
        }

        if (line.hasOption(httpsPort.getOpt())) {
            tomcat7Runner.httpsPort = Integer.parseInt(line.getOptionValue(httpsPort.getOpt()));
        }
		// ajp端口号
        if (line.hasOption(ajpPort.getOpt())) {
            tomcat7Runner.ajpPort = Integer.parseInt(line.getOptionValue(ajpPort.getOpt()));
        }

        if (line.hasOption(resetExtract.getOpt())) {
            tomcat7Runner.resetExtract = true;
        }

        if (line.hasOption(debug.getOpt())) {
            tomcat7Runner.debug = true;
        }

        if (line.hasOption(httpProtocol.getOpt())) {
            tomcat7Runner.httpProtocol = line.getOptionValue(httpProtocol.getOpt());
        }

        if (line.hasOption(sysProps.getOpt())) {
            Properties systemProperties = line.getOptionProperties(sysProps.getOpt());
            if (systemProperties != null && !systemProperties.isEmpty()) {
                Iterator i$ = systemProperties.entrySet().iterator();

                while(i$.hasNext()) {
                    Entry<Object, Object> sysProp = (Entry)i$.next();
                    System.setProperty((String)sysProp.getKey(), (String)sysProp.getValue());
                }
            }
        }

        if (line.hasOption(clientAuth.getOpt())) {
            tomcat7Runner.clientAuth = clientAuth.getOpt();
        }

        if (line.hasOption(keyAlias.getOpt())) {
            tomcat7Runner.keyAlias = line.getOptionValue(keyAlias.getOpt());
        }

        if (line.hasOption(extractDirectory.getOpt())) {
            tomcat7Runner.extractDirectory = line.getOptionValue(extractDirectory.getOpt());
        }
		//loggerName 日志配置
        if (line.hasOption(loggerName.getOpt())) {
            tomcat7Runner.loggerName = line.getOptionValue(loggerName.getOpt());
        }
		//uriEncoding 編碼配置
        if (line.hasOption(uriEncoding.getOpt())) {
            tomcat7Runner.uriEncoding = line.getOptionValue(uriEncoding.getOpt());
        }
		// 一直到這裡, 都是關于tomcat的一些配置,這些相對無關緊要,
		// run 方法請看下一段代碼
        tomcat7Runner.run();
    }

    private static Properties buildStandaloneProperties() throws IOException {
        InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("tomcat.standalone.properties");
        Properties properties = new Properties();
        properties.load(is);
        return properties;
    }

    public static String getCmdLineSyntax() {
        return "java -jar [path to your exec war jar]";
    }

    static {
        OptionBuilder.withArgName("httpPort");
        OptionBuilder.hasArg();
        OptionBuilder.withDescription("http port to use");
        httpPort = OptionBuilder.create("httpPort");
        OptionBuilder.withArgName("httpsPort");
        OptionBuilder.hasArg();
        OptionBuilder.withDescription("https port to use");
        httpsPort = OptionBuilder.create("httpsPort");
        OptionBuilder.withArgName("ajpPort");
        OptionBuilder.hasArg();
        OptionBuilder.withDescription("ajp port to use");
        ajpPort = OptionBuilder.create("ajpPort");
        OptionBuilder.withArgName("serverXmlPath");
        OptionBuilder.hasArg();
        OptionBuilder.withDescription("server.xml to use, optional");
        serverXmlPath = OptionBuilder.create("serverXmlPath");
        OptionBuilder.withArgName("resetExtract");
        OptionBuilder.withDescription("clean previous extract directory");
        resetExtract = OptionBuilder.create("resetExtract");
        OptionBuilder.withLongOpt("help");
        OptionBuilder.withDescription("help");
        help = OptionBuilder.create('h');
        OptionBuilder.withLongOpt("debug");
        OptionBuilder.withDescription("debug");
        debug = OptionBuilder.create('X');
        OptionBuilder.withDescription("use value for given property");
        OptionBuilder.hasArgs();
        OptionBuilder.withDescription("key=value");
        OptionBuilder.withValueSeparator();
        sysProps = OptionBuilder.create('D');
        OptionBuilder.withArgName("clientAuth");
        OptionBuilder.withDescription("enable client authentication for https");
        clientAuth = OptionBuilder.create("clientAuth");
        OptionBuilder.withArgName("keyAlias");
        OptionBuilder.hasArgs();
        OptionBuilder.withDescription("alias from keystore for ssl");
        keyAlias = OptionBuilder.create("keyAlias");
        OptionBuilder.withArgName("password");
        OptionBuilder.hasArgs();
        OptionBuilder.withDescription("obfuscate the password and exit");
        obfuscate = OptionBuilder.create("obfuscate");
        OptionBuilder.withArgName("httpProtocol");
        OptionBuilder.hasArg();
        OptionBuilder.withDescription("http protocol to use: HTTP/1.1 or org.apache.coyote.http11.Http11NioProtocol");
        httpProtocol = OptionBuilder.create("httpProtocol");
        OptionBuilder.withArgName("extractDirectory");
        OptionBuilder.hasArg();
        OptionBuilder.withDescription("path to extract war content, default value: .extract");
        extractDirectory = OptionBuilder.create("extractDirectory");
        OptionBuilder.withArgName("loggerName");
        OptionBuilder.hasArg();
        OptionBuilder.withDescription("logger to use: slf4j to use slf4j bridge on top of jul");
        loggerName = OptionBuilder.create("loggerName");
        OptionBuilder.withArgName("uriEncoding");
        OptionBuilder.hasArg();
        OptionBuilder.withDescription("connector uriEncoding default ISO-8859-1");
        uriEncoding = OptionBuilder.create("uriEncoding");
        options = new Options();
        options.addOption(httpPort).addOption(httpsPort).addOption(ajpPort).addOption(serverXmlPath).addOption(resetExtract).addOption(help).addOption(debug).addOption(sysProps).addOption(httpProtocol).addOption(clientAuth).addOption(keyAlias).addOption(obfuscate).addOption(extractDirectory).addOption(loggerName).addOption(uriEncoding);
    }
}

           
package org.apache.tomcat.maven.runner;

public class Tomcat7Runner  {

    public static final String USE_SERVER_XML_KEY = "useServerXml";
    public static final String WARS_KEY = "wars";
    public static final String ARCHIVE_GENERATION_TIMESTAMP_KEY = "generationTimestamp";
    public static final String ENABLE_NAMING_KEY = "enableNaming";
    public static final String ACCESS_LOG_VALVE_FORMAT_KEY = "accessLogValveFormat";
    public static final String CODE_SOURCE_CONTEXT_PATH = "codeSourceContextPath";
    public static final String HTTP_PROTOCOL_KEY = "connectorhttpProtocol";
    public static final String HTTP_PORT_KEY = "httpPort";
    public int httpPort;
    public int httpsPort;
    public int ajpPort;
    public String serverXmlPath;
    public Properties runtimeProperties;
    public boolean resetExtract;
    public boolean debug = false;
    public String clientAuth = "false";
    public String keyAlias = null;
    public String httpProtocol;
    public String extractDirectory = ".extract";
    public File extractDirectoryFile;
    public String codeSourceContextPath = null;
    public File codeSourceWar = null;
    public String loggerName;
    Catalina container;
    Tomcat tomcat;
    String uriEncoding = "ISO-8859-1";
    Map<String, String> webappWarPerContext = new HashMap();

    public Tomcat7Runner() {
    }
public void run() throws Exception {
        PasswordUtil.deobfuscateSystemProps();
        if(this.loggerName != null && this.loggerName.length() > 0) {
            this.installLogger(this.loggerName);
        }

        this.extractDirectoryFile = new File(this.extractDirectory);
        this.debugMessage("use extractDirectory:" + this.extractDirectoryFile.getPath());
        boolean archiveTimestampChanged = false;
		// 擷取目前目錄tomcat_executable_archive.timestamp配置檔案,這個檔案在servlettest-1.0-SNAPSHOT-war-exec.jar 中打開就可以發現
		// 為了友善我貼上配置檔案的内容,突然一看配置檔案我很是懵逼。
		// #created by Apache Tomcat Maven plugin
		//#Tue Apr 16 21:39:05 CST 2019
		//generationTimestamp=1555421945264
		//accessLogValveFormat=%h %l %u %t %r %s %b %I %D
		//enableNaming=false
		//useServerXml=false
		//wars=.war|/
		//connectorhttpProtocol=HTTP/1.1
        File timestampFile = new File(this.extractDirectoryFile, ".tomcat_executable_archive.timestamp");
        Properties timestampProps = this.loadProperties(timestampFile);
        String wars;
        if(timestampFile.exists()) {
            wars = timestampProps.getProperty("generationTimestamp");
            if(wars != null) {
                long timestamp = Long.parseLong(wars);
                archiveTimestampChanged = Long.parseLong(this.runtimeProperties.getProperty("generationTimestamp")) > timestamp;
                this.debugMessage("read timestamp from file " + wars + ", archiveTimestampChanged: " + archiveTimestampChanged);
            }
        }

        this.codeSourceContextPath = this.runtimeProperties.getProperty("codeSourceContextPath");
        if(this.codeSourceContextPath != null && !this.codeSourceContextPath.isEmpty()) {
            this.codeSourceWar = (File)AccessController.doPrivileged(new PrivilegedAction<File>() {
                public File run() {
                    try {
                        File src = new File(Tomcat7Runner.class.getProtectionDomain().getCodeSource().getLocation().toURI());
                        if(src.getName().endsWith(".war")) {
                            return src;
                        }

                        Tomcat7Runner.this.debugMessage("ERROR: Code source is not a war file, ignoring.");
                    } catch (URISyntaxException var2) {
                        Tomcat7Runner.this.debugMessage("ERROR: Could not find code source. " + var2.getMessage());
                    }

                    return null;
                }
            });
        }

        if(this.extractDirectoryFile.exists() && !this.resetExtract && !archiveTimestampChanged) {
            wars = this.runtimeProperties.getProperty("wars");
            this.populateWebAppWarPerContext(wars);
        } else {
            this.extract();
            if(archiveTimestampChanged || !timestampFile.exists()) {
                timestampProps.put("generationTimestamp", this.runtimeProperties.getProperty("generationTimestamp"));
                this.saveProperties(timestampProps, timestampFile);
            }
        }
		// 以上都是對配置檔案做的處理
		// 下面這幾行看到特别熟悉,這應該就是建立基本的tomcat目錄
        (new File(this.extractDirectory, "conf")).mkdirs();
        (new File(this.extractDirectory, "logs")).mkdirs();
        (new File(this.extractDirectory, "webapps")).mkdirs();
        (new File(this.extractDirectory, "work")).mkdirs();
        File tmpDir = new File(this.extractDirectory, "temp");
        tmpDir.mkdirs();
        System.setProperty("java.io.tmpdir", tmpDir.getAbsolutePath());
        System.setProperty("catalina.base", this.extractDirectoryFile.getAbsolutePath());
        System.setProperty("catalina.home", this.extractDirectoryFile.getAbsolutePath());
        if(this.serverXmlPath == null && !this.useServerXml()) {
            this.tomcat = new Tomcat() {
				//看到這裡,想到之前在server.xml中配置的xml資訊是不是一目了然
				//<Context path="/aaa" docBase="E:\webapp\servlettest\target\servlettest-1.0-SNAPSHOT">
				//</Context>
                public Context addWebapp(Host host, String url, String name, String path) {
                    Context ctx = new StandardContext();
                    ctx.setName(name);
                    ctx.setPath(url);
                    ctx.setDocBase(path);
                    ContextConfig ctxCfg = new ContextConfig();
                    ctx.addLifecycleListener(ctxCfg);
                    ctxCfg.setDefaultWebXml((new File(Tomcat7Runner.this.extractDirectory, "conf/web.xml")).getAbsolutePath());
                    if(host == null) {
                        this.getHost().addChild(ctx);
                    } else {
                        host.addChild(ctx);
                    }

                    return ctx;
                }
            };
            if(this.enableNaming()) {
                System.setProperty("catalina.useNaming", "true");
                this.tomcat.enableNaming();
            }

            this.tomcat.getHost().setAppBase((new File(this.extractDirectory, "webapps")).getAbsolutePath());
            String connectorHttpProtocol = this.runtimeProperties.getProperty("connectorhttpProtocol");
            if(this.httpProtocol != null && this.httpProtocol.trim().length() > 0) {
                connectorHttpProtocol = this.httpProtocol;
            }
			
            this.debugMessage("use connectorHttpProtocol:" + connectorHttpProtocol);
			//以下在代碼在server.xml中基本都能找到對應配置例如下面這個
            if(this.httpPort > 0) {
				//這裡對應servet.xml 的這段配置
				//<Connector port="8080" protocol="HTTP/1.1"
               //        connectionTimeout="20000"
               //				redirectPort="8443" />  
			   //
                Connector connector = new Connector(connectorHttpProtocol);
                connector.setPort(this.httpPort);
                if(this.httpsPort > 0) {
                    connector.setRedirectPort(this.httpsPort);
                }

                connector.setURIEncoding(this.uriEncoding);
                this.tomcat.getService().addConnector(connector);
                this.tomcat.setConnector(connector);
            }

            AccessLogValve alv = new AccessLogValve();
            alv.setDirectory((new File(this.extractDirectory, "logs")).getAbsolutePath());
            alv.setPattern(this.runtimeProperties.getProperty("accessLogValveFormat"));
            this.tomcat.getHost().getPipeline().addValve(alv);
            Connector httpsConnector;
            String baseDir;
            String context;
            if(this.httpsPort > 0) {
                httpsConnector = new Connector(connectorHttpProtocol);
                httpsConnector.setPort(this.httpsPort);
                httpsConnector.setSecure(true);
                httpsConnector.setProperty("SSLEnabled", "true");
                httpsConnector.setProperty("sslProtocol", "TLS");
                httpsConnector.setURIEncoding(this.uriEncoding);
                String keystoreFile = System.getProperty("javax.net.ssl.keyStore");
                baseDir = System.getProperty("javax.net.ssl.keyStorePassword");
                context = System.getProperty("javax.net.ssl.keyStoreType", "jks");
                if(keystoreFile != null) {
                    httpsConnector.setAttribute("keystoreFile", keystoreFile);
                }

                if(baseDir != null) {
                    httpsConnector.setAttribute("keystorePass", baseDir);
                }

                httpsConnector.setAttribute("keystoreType", context);
                String truststoreFile = System.getProperty("javax.net.ssl.trustStore");
                String truststorePass = System.getProperty("javax.net.ssl.trustStorePassword");
                String truststoreType = System.getProperty("javax.net.ssl.trustStoreType", "jks");
                if(truststoreFile != null) {
                    httpsConnector.setAttribute("truststoreFile", truststoreFile);
                }

                if(truststorePass != null) {
                    httpsConnector.setAttribute("truststorePass", truststorePass);
                }

                httpsConnector.setAttribute("truststoreType", truststoreType);
                httpsConnector.setAttribute("clientAuth", this.clientAuth);
                httpsConnector.setAttribute("keyAlias", this.keyAlias);
                this.tomcat.getService().addConnector(httpsConnector);
                if(this.httpPort <= 0) {
                    this.tomcat.setConnector(httpsConnector);
                }
            }

            if(this.ajpPort > 0) {
                httpsConnector = new Connector("org.apache.coyote.ajp.AjpProtocol");
                httpsConnector.setPort(this.ajpPort);
                httpsConnector.setURIEncoding(this.uriEncoding);
                this.tomcat.getService().addConnector(httpsConnector);
            }

            Iterator i$ = this.webappWarPerContext.entrySet().iterator();

            while(i$.hasNext()) {
                Entry<String, String> entry = (Entry)i$.next();
                baseDir = null;
                context = null;
                Context context;
                if(((String)entry.getKey()).equals("/")) {
                    baseDir = (new File(this.extractDirectory, "webapps/ROOT.war")).getAbsolutePath();
                    context = this.tomcat.addWebapp("", baseDir);
                } else {
                    baseDir = (new File(this.extractDirectory, "webapps/" + (String)entry.getValue())).getAbsolutePath();
                    context = this.tomcat.addWebapp((String)entry.getKey(), baseDir);
                }

                URL contextFileUrl = this.getContextXml(baseDir);
                if(contextFileUrl != null) {
                    context.setConfigFile(contextFileUrl);
                }
            }

            if(this.codeSourceWar != null) {
                String baseDir = (new File(this.extractDirectory, "webapps/" + this.codeSourceWar.getName())).getAbsolutePath();
                Context context = this.tomcat.addWebapp(this.codeSourceContextPath, baseDir);
                URL contextFileUrl = this.getContextXml(baseDir);
                if(contextFileUrl != null) {
                    context.setConfigFile(contextFileUrl);
                }
            }

            this.tomcat.start();
            Runtime.getRuntime().addShutdownHook(new Tomcat7Runner.TomcatShutdownHook());
        } else {
            this.container = new Catalina();
            this.container.setUseNaming(this.enableNaming());
            if(this.serverXmlPath != null && (new File(this.serverXmlPath)).exists()) {
                this.container.setConfig(this.serverXmlPath);
            } else {
                this.container.setConfig((new File(this.extractDirectory, "conf/server.xml")).getAbsolutePath());
            }

            this.container.start();
        }
		//  大家知道正常情況下一個main方法執行完了結束了
		// 可是這也是一個main方法卻不會結束,就是這行代碼可以使main方法處與等待狀态
        this.waitIndefinitely();
    }
    
}