JavaWeb学习之——Tomcat篇之启动过程解析
博客专区 > lizo 的博客 > 博客详情
JavaWeb学习之——Tomcat篇之启动过程解析
lizo 发表于1年前
JavaWeb学习之——Tomcat篇之启动过程解析
  • 发表于 1年前
  • 阅读 19
  • 收藏 4
  • 点赞 0
  • 评论 0

新睿云服务器60天免费使用,快来体验!>>>   

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函数在这里)

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启动代码

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

分别对应的Catalina的setAwait(),load(),start()方法。

  • 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==>Lifecycle

start()方法是在LifecycleBase中

@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()方法,改方法的主要作为就是

@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()                             |
 * ----»-----------------------------»------------------------------
 *

 

标签: Tomcat
  • 打赏
  • 点赞
  • 收藏
  • 分享
共有 人打赏支持
粉丝 55
博文 39
码字总数 48903
×
lizo
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: