文档章节

JavaWeb学习之——Tomcat篇之启动过程解析

lizo
 lizo
发布于 2016/12/06 21:02
字数 1105
阅读 24
收藏 4

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

 

© 著作权归作者所有

共有 人打赏支持
lizo
粉丝 59
博文 39
码字总数 48903
作品 0
杭州
程序员
深入分析JavaWeb Item1 -- JavaWeb开发入门

一、基本概念 1.1、WEB开发的相关知识   WEB,在英语中web即表示网页的意思,它用于表示Internet主机上供外界访问的资源。   Internet上供外界访问的Web资源分为: 静态web资源(如html ...

小平果
2017/11/29
0
0
深入分析JavaWeb Item2 -- Tomcat服务器学习和使用

一、Tomcat服务器端口的配置   Tomcat的所有配置都放在文件夹之中,里面的文件是配置的核心文件。   如果想修改Tomcat服务器的启动端口,则可以在配置文件中的节点进行的端口修改 例如:...

小平果
2017/11/29
0
0
一、JavaWeb总结:JavaWeb开发相关概念与常见web服务器

一、基本概念 1.1、WEB开发的相关知识   WEB,在英语中web即表示网页的意思,它用于表示Internet主机上供外界访问的资源。   Internet上供外界访问的Web资源分为: 静态web资源(如html ...

AAASSSSddd
2016/08/17
27
0
二、JavaWeb总结:Tomcat服务器的学习和使用

一、Tomcat服务器端口的配置   Tomcat的所有配置都放在conf文件夹之中,里面的server.xml文件是配置的核心文件。   如果想修改Tomcat服务器的启动端口,则可以在server.xml配置文件中的C...

AAASSSSddd
2016/08/17
15
0
《深入探索Netty原理及源码分析》文集小结

写在2017年末尾,翻看文集的第一篇文章已经是三个月前的事了,也没想过这文集会写那么久,这么慢。。。 Netty文集中的文章主要都是我学习过程的笔记,写博客的主要目的是为了通过输出来倒逼输...

tomas家的小拨浪鼓
2017/12/30
0
0

没有更多内容

加载失败,请刷新页面

加载更多

20180920 rzsz传输文件、用户和用户组相关配置文件与管理

利用rz、sz实现Linux与Windows互传文件 [root@centos01 ~]# yum install -y lrzsz # 安装工具sz test.txt # 弹出对话框,传递到选择的路径下rz # 回车后,会从对话框中选择对应的文件传递...

野雪球
今天
2
0
OSChina 周四乱弹 —— 毒蛇当辣条

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @ 达尔文:分享花澤香菜/前野智昭/小野大輔/井上喜久子的单曲《ミッション! 健?康?第?イチ》 《ミッション! 健?康?第?イチ》- 花澤香菜/前野智...

小小编辑
今天
7
3
java -jar运行内存设置

java -Xms64m #JVM启动时的初始堆大小 -Xmx128m #最大堆大小 -Xmn64m #年轻代的大小,其余的空间是老年代 -XX:MaxMetaspaceSize=128m # -XX:CompressedClassSpaceSize=6...

李玉长
今天
4
0
Spring | 手把手教你SSM最优雅的整合方式

HEY 本节主要内容为:基于Spring从0到1搭建一个web工程,适合初学者,Java初级开发者。欢迎与我交流。 MODULE 新建一个Maven工程。 不论你是什么工具,选这个就可以了,然后next,直至finis...

冯文议
今天
2
0
RxJS的另外四种实现方式(四)——性能最高的库(续)

接上一篇RxJS的另外四种实现方式(三)——性能最高的库 上一篇文章我展示了这个最高性能库的实现方法。下面我介绍一下这个性能提升的秘密。 首先,为了弄清楚Most库究竟为何如此快,我必须借...

一个灰
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部