JavaWeb學習之——Tomcat篇之啓動過程解析

Tomcat 基本接口

  1. Tomcat 中最頂層的容器叫Server,表明整個服務器,Server中包含至少一個Service
  2. Service 主要有 Connector和Container組成
  3. Connector負責網絡鏈接,request/response的建立等
  4. Container負責具體的Servlet處理
  5. 一個Server能夠包含多個Service(多個Application),一個Service只有一個Container,但能夠有多個Connector
  6. Tomcat中的Server由Catalina來管理,Catalina管理Tomcat的生命週期

入口

Bootstrap是Tomcat的入口(main函數在這裏)spring

public static void main(String args[]) {

    if (daemon == null) {
        Bootstrap bootstrap = new Bootstrap();
        try {
            //初始化ClassLoader,而且使用ClassLoader建立Catalina實例,而後
            //賦值給catalinaDaemon
            bootstrap.init();
        } catch (Throwable t) {
            handleThrowable(t);
            t.printStackTrace();
            return;
        }
        daemon = bootstrap;
    } else {
        Thread.currentThread().setContextClassLoader(daemon.catalinaLoader);
    }

    try {
        String command = "start";
        if (args.length > 0) {
            command = args[args.length - 1];
        }
    
        /*daemon的load(),start(),setAwait()等方
        法都是利用反射調用Catalina中的方法*/
        if (command.equals("startd")) {
            args[args.length - 1] = "start";
            daemon.load(args);
            daemon.start();
        } else if (command.equals("stopd")) {
            args[args.length - 1] = "stop";
            daemon.stop();
        } else if (command.equals("start")) {
            daemon.setAwait(true);
            daemon.load(args);
            daemon.start();
        } else if (command.equals("stop")) {
            daemon.stopServer(args);
        } else if (command.equals("configtest")) {
            daemon.load(args);
            if (null==daemon.getServer()) {
                System.exit(1);
            }
            System.exit(0);
        } else {
            log.warn("Bootstrap: command \"" + command + "\" does not exist.");
        }
    } catch (Throwable t) {
        // Unwrap the Exception for clearer error reporting
        if (t instanceof InvocationTargetException &&
                t.getCause() != null) {
            t = t.getCause();
        }
        handleThrowable(t);
        t.printStackTrace();
        System.exit(1);
    }

}

Catalina的啓動過程

從上面的代碼中看出,Tomcat啓動代碼bootstrap

daemon.setAwait(true);
daemon.load(args);
daemon.start();

分別對應的Catalina的setAwait(),load(),start()方法。tomcat

  • Catalina的setAwait()的方法經過設置一個標誌位,在服務器啓動的時候是否進入等待狀態
  • load()是讀取相關的配置文件
  • start()主要的功能是啓動Server,調用Server的start()
public void start() {

   ...
    try {
        //調用Server的start()方法
        getServer().start();
    } catch (LifecycleException e) {
        log.fatal(sm.getString("catalina.serverStartFail"), e);
        try {
            getServer().destroy();
        } catch (LifecycleException e1) {
            log.debug("destroy() failed for failed Server ", e1);
        }
        return;
    }

    ...
    //經過setAwait(),設置await = true
    if (await) {
        await();
        stop();
    }
}

Server的啓動

Catalina的啓動,實際上是調用Server的Start()方法,Server的默認實現是StartardServer。服務器

繼承關係:網絡

StartardServer ==> LifecycleMBeanBase ==>LifecycleBase==>Lifecycleapp

start()方法是在LifecycleBase中ide

@Override
public final synchronized void start() throws LifecycleException {

    ...

    if (state.equals(LifecycleState.NEW)) {
        init();
    } else if (state.equals(LifecycleState.FAILED)) {
        stop();
    } else if (!state.equals(LifecycleState.INITIALIZED) &&
            !state.equals(LifecycleState.STOPPED)) {
        invalidTransition(Lifecycle.BEFORE_START_EVENT);
    }

    ...
        setStateInternal(LifecycleState.STARTING_PREP, null, false);
        startInternal();
        ...
    
}

這個類是一個模板類,在init() 中調用了initInternal(),而後啓動的時候調用startInternal(),而這2個方法是在StartardServer中實現。有點相似Spring的AbstractApplicationContext. 而後看一下StardardServer中的initInternal()和startInternal()方法,其實這2個方法就是對本身的Service進行初始化和啓動函數

protected void initInternal() throws LifecycleException {

    super.initInternal();

    ...
    // Initialize our defined Services
    for (int i = 0; i < services.length; i++) {
        services[i].init();
    }
}
@Override
protected void startInternal() throws LifecycleException {

    // Start our defined Services
    synchronized (servicesLock) {
        for (int i = 0; i < services.length; i++) {
            services[i].start();
        }
    }
}

在Catalina啓動的後,還有一個await()的方法,也是調用StandardServer的await()方法,改方法的主要做爲就是spa

@Override
public void await() {
    if( port == -2 ) {
        return;
    }
    if( port==-1 ) {
        try {
            awaitThread = Thread.currentThread();
            while(!stopAwait) {
                try {
                    Thread.sleep( 10000 );
                } catch( InterruptedException ex ) {
                }
            }
        } finally {
            awaitThread = null;
        }
        return;
    }
    
    ...
    awaitSocket = new ServerSocket(port, 1,
                    InetAddress.getByName(address));
    ···
    boolean match = command.toString().equals(shutdown);
    if (match) {
        log.info(sm.getString("standardServer.shutdownViaPort"));
                    break;
    } else
        log.warn("StandardServer.await: Invalid command '"
                + command.toString() + "' received");

當爲-1和-2的時候進行特殊處理,不然監聽端口(默認8005),若是收到"SHUTDOWN"消息則關閉Tomcat線程

Service啓動

Service的默認實現是StandardService,同時StandardService也繼承自LifecycleMBeanBase(嗯,和StandardServer同樣的生命週期管理)

@Override
protected void startInternal() throws LifecycleException {

    ...
    // Start our defined Container first
    if (container != null) {
        synchronized (container) {
            container.start();
        }
    }

    synchronized (executors) {
        for (Executor executor: executors) {
            executor.start();
        }
    }

    mapperListener.start();

    // Start our defined Connectors second
    synchronized (connectorsLock) {
        for (Connector connector: connectors) {
            if (connector.getState() != LifecycleState.FAILED) {
                connector.start();
            }
        }
    }
}

initInternal()的方式和startInternal()的方式差很少,也是調用Container、executors、mapperListener、connector的init()的方法。

  • container和connector前面說過
  • mapperListener Mapper的監聽器,能夠監聽container容器的變化
  • executors是在connectors中管理線程的線程池,在serverx.xml的配置中默認是註釋掉的

能夠看出tomcat的啓動順序以下圖

Lifecycle

Lifecycle是tomcat用於生命週期管理的接口

Lifecycle總共有13常量,用於區別13中事件,默認的實現是LifecycleBase。原理應該比較好理解,當一些事件觸發的時候,會觸發類去執行相對應的操做(例如 start的時候,會根據事件到底執行init()仍是stop())。

爲了方便擴展,咱們還能夠註冊LifecycleListener,把這些監聽器加入(addLifecycleListnener方法)監聽,當事件觸發的時候,同時還會觸發這些監聽器對應的處理。(spring boot中在啓動的時候也用到相同方法),Lifecycle的註釋中說明了哪些事件會調用哪些方法

*            start()
 *  -----------------------------
 *  |                           |
 *  | init()                    |
 * NEW -»-- INITIALIZING        |
 * | |           |              |     ------------------«-----------------------
 * | |           |auto          |     |                                        |
 * | |          \|/    start() \|/   \|/     auto          auto         stop() |
 * | |      INITIALIZED --»-- STARTING_PREP --»- STARTING --»- STARTED --»---  |
 * | |         |                                                            |  |
 * | |destroy()|                                                            |  |
 * | --»-----«--    ------------------------«--------------------------------  ^
 * |     |          |                                                          |
 * |     |         \|/          auto                 auto              start() |
 * |     |     STOPPING_PREP ----»---- STOPPING ------»----- STOPPED -----»-----
 * |    \|/                               ^                     |  ^
 * |     |               stop()           |                     |  |
 * |     |       --------------------------                     |  |
 * |     |       |                                              |  |
 * |     |       |    destroy()                       destroy() |  |
 * |     |    FAILED ----»------ DESTROYING ---«-----------------  |
 * |     |                        ^     |                          |
 * |     |     destroy()          |     |auto                      |
 * |     --------»-----------------    \|/                         |
 * |                                 DESTROYED                     |
 * |                                                               |
 * |                            stop()                             |
 * ----»-----------------------------»------------------------------
 *
相關文章
相關標籤/搜索