文档章节

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

lizo
 lizo
发布于 2016/12/06 21:02
字数 1105
阅读 23
收藏 4
点赞 0
评论 0

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
粉丝 58
博文 39
码字总数 48903
作品 0
杭州
程序员
深入分析JavaWeb Item1 -- JavaWeb开发入门

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

小平果
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 Item2 -- Tomcat服务器学习和使用

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

小平果
2017/11/29
0
0
《深入探索Netty原理及源码分析》文集小结

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

tomas家的小拨浪鼓
2017/12/30
0
0
二、JavaWeb总结:Tomcat服务器的学习和使用

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

AAASSSSddd
2016/08/17
15
0
史上最简单的 Spring MVC 教程(九)

1 前言 在史上最简单的 Spring MVC 教程(五、六、七、八)等四篇博文中,咱们已经分别实现了“人员列表”的显示、添加、修改和删除等常见的增、删、改、查功能。接下来,也就是在本篇博文中...

qq_35246620
2017/01/29
0
0
Tomcat安装与war应用发布

作为一个Javaweb服务器,安装Tomcat之前需要先安装jdk。 1.Tomcat下载 百度搜索Tomcat 点击第一个链接即可 左侧download下有可供选择的版本,由于本人使用的IDE没有支持到Tomcat9,因此喜欢用...

think道
03/25
0
0
JavaWeb学习之——Tomcat篇Connector

概述 Tomcat最底层是使用Socket来进行连接的,而Connector的作用就是将接受到的请求转换为Request和Response。Request和Response是按照HTTP协议来封装的,封装完成后就交给Container进行处理...

lizo
2016/12/21
8
0
Eclipse中Tomcat配置问题

前言: 昨天用javaSE手动部署了一个servlet,本以为自己已经初步窥探了,结果一用eclipse生成javaweb项目 然后部署到Tomcat就问题多多。这一天也算是栽在这上面了。 java后台自学ing的弊端就...

codingcoge
06/07
0
0
Tomcat源码解读系列(二)——Tomcat的核心组成和启动过程

如果要用一张图来形象展现一下Tomcat组成的话,整个Tomcat的组成可以如下图所示: Tomcat在接收到用户请求时,将会通过以上组件的协作来给最终用户产生响应。 首先是最外层的Server和Service...

heroShane
2014/02/07
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

TensorFlow 线性分类

构造直线 z = 2 * x - 3 * y + 4 x0*w0+x1*w1+b=0 x1=-x0* w0/w1-b/w1 斜率 k= -w0/w1 截距 -b/w1 随机生成数据,加入一定的偏差,用直线将二维平面分为两部分 使用线性模型拟合参数 损失函数...

阿豪boy
9分钟前
0
0
翻译冒泡排序测试

翻译一个冒泡排序: var a = [1,3,2,4,6,5];var f = 0;var n = a.length ;for( var i =1; i<= n; i++) { for( var j = n-1 ; j >= i; j --) { if(a[j] < a[j+1]) { ......

钟元OSS
10分钟前
0
0
maven父、子级版本号同时修改

命令: mvn versions:set -DnewVersion=0.0.2-SNAPSHOT

沉默的懒猫
12分钟前
0
0
Spring boot中的异常处理之注解响应

Controller层 return patientRepository.findById(id) .orElseThrow(() -> new NotFoundException(String.format("Patient %d not found", id))); Exception类 @ResponseS......

亚林瓜子
13分钟前
0
0
webpack文档翻译_001

概念 webpack是一个为现代JavaScript应用的打包工具(a static module bundler)。 当webpack处理应用时,在其内部,会生成一个依赖图(dependency graph),这个依赖图可以映射到项目里的每一个...

DennisHill
13分钟前
5
0
vim 行首/行尾 批量操作

批量插入 行首插入 :%s/^/your_word/ 行尾插入:%s/$/your_word/ 按键操作 注释:ctrl+v 进入列编辑模式,向下或向上移动光标,把需要注释的行的开头标记起来,然后按大写的I(shift + i),再插入...

温子寒
14分钟前
0
0
Java语言学习(十二):多线程

Java中给多线程编程提供了内置的支持,多线程是多任务的一种特别形式,它使用了更小的资源开销。这里需要知道两个术语及其关系:进程和线程。 进程:进程是系统进行资源分配和调度的一个独立...

海岸线的曙光
20分钟前
0
0
mysql源码阅读相关文章

https://www.jianshu.com/p/e739afb8fe31

writeademo
33分钟前
0
0
CentOS7 安装MySQL8

1. 从官网拿到本地YUM源的安装包,并安装本地YUM源 2. 通过`yum install -y`命令进行MySQL的安装 3. 启动服务,并配置开机自启 4. 获取初始化密码,登录MySQL 5. 修改密码策略,然后自行设置roo...

小致dad
39分钟前
0
0
史上最简单的 IntelliJ IDEA 教程

我不是作者,我只是内容的搬运工。 传送门

颖辉小居
41分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部