文档章节

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

lizo
 lizo
发布于 2016/12/06 21:02
字数 1105
阅读 25
收藏 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
粉丝 60
博文 40
码字总数 50118
作品 0
杭州
程序员
私信 提问
深入分析JavaWeb Item1 -- JavaWeb开发入门

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

小平果
2017/11/29
0
0
使用 Dockerfile定制Java Web镜像

一、前言 对使用 Docker 搭建 Java Web 运行环境(利用 commit 理解镜像构成 来源:黄勇 )博文的归纳: 1、启动容器: docker run <相关参数> <镜像 ID> <初始命令> -i:表示以“交互模式”运...

吴伟祥
11/16
0
0
一、JavaWeb总结:JavaWeb开发相关概念与常见web服务器

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

AAASSSSddd
2016/08/17
27
0
深入分析JavaWeb Item2 -- Tomcat服务器学习和使用

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

小平果
2017/11/29
0
0
二、JavaWeb总结:Tomcat服务器的学习和使用

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

AAASSSSddd
2016/08/17
15
0

没有更多内容

加载失败,请刷新页面

加载更多

deepin中配置robot framework环境

本文永久更新地址:https://my.oschina.net/bysu/blog/2989005 【若要到岸,请摇船:开源中国 不最醉不龟归】 1.在终端中输入pip,回车,如果提示没有该命令,则先安转pip sudo apt-get inst...

不最醉不龟归
33分钟前
2
0
OSChina 周日乱弹 —— 钱不还,我就当你人不在了

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @莱布妮子 :分享Bigleaf的单曲《小鹿》 《小鹿》- Bigleaf 手机党少年们想听歌,请使劲儿戳(这里) 周日在家做什么? 做手工呀, @poorfis...

小小编辑
今天
114
4
EOS docker开发环境

使用eos docker镜像是部署本地EOS开发环境的最轻松愉快的方法。使用官方提供的eos docker镜像,你可以快速建立一个eos开发环境,可以迅速启动开发节点和钱包服务器、创建账户、编写智能合约....

汇智网教程
今天
20
0
《唐史原来超有趣》的读后感优秀范文3700字

《唐史原来超有趣》的读后感优秀范文3700字: 作者:花若离。我今天分享的内容《唐史原来超有趣》这本书的读后感,我将这本书看了一遍之后就束之高阁了,不过里面的内容一直在在脑海中回放,...

原创小博客
今天
30
0
IC-CAD Methodology知识图谱

CAD (Computer Aided Design),计算机辅助设计,指利用计算机及其图形设备帮助设计人员进行设计工作,这个定义同样可以用来近似描述IC公司CAD工程师这个岗位的工作。 早期IC公司的CAD岗位最初...

李艳青1987
今天
39
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部