# 利刃出鞘_Tomcat 核心原理解析(三)

利刃出鞘_Tomcat 核心原理解析(三)

一、 Tomcat专题 - Tomcat架构 - 启动流程

1、Tomcat 启动流程

2、Tomcat 启动 步骤 :

1) 启动tomcat , 需要调用 bin/startup.bat (在linux 目录下 , 需要调用 bin/startup.sh) ,在startup.bat 脚本中, 调用了catalina.bat。

2) 在catalina.bat 脚本文件中,调用了BootStrap 中的main方法。

3)在BootStrap 的main 方法中调用了 init 方法 , 来创建Catalina 及 初始化类加载器。

4)在BootStrap 的main 方法中调用了 load 方法 , 在其中又调用了Catalina的load方法。

5)在Catalina 的load 方法中 , 需要进行一些初始化的工作, 并需要构造Digester 对象, 用于解析 XML。

6) 然后在调用后续组件的初始化操作 。。。

加载 Tomcat 的配置文件,初始化容器组件 ,监听对应的端口号, 准备接受客户端请求。

二、 Tomcat专题 - Tomcat架构 - 启动流程 - 涉及组件介绍

1、源码解析 Lifecycle

由于所有的组件均存在初始化、启动、停止等生命周期方法,拥有生命周期管理的特性, 所以 Tomcat 在设计的时候, 基于生命周期管理抽象成了一个接口 Lifecycle ,而组件 Server、Service、Container、Executor、Connector 组件 , 都实现了一个生命周期的接口,从而具有了以下生命周期中的核心方法:

1) init():初始化组件。

2) start():启动组件。

3) stop():停止组件。

4) destroy():销毁组件。

2、各组件的默认实现

Server、Service、Engine、Host、Context 都是接口, 下图中罗列了这些接口的默认实现类。当前对于 Endpoint 组件来说,在 Tomcat 中没有对应的 Endpoint 接口, 但是有一个抽象类 AbstractEndpoint ,其下有三个实现类: NioEndpoint、Nio2Endpoint、AprEndpoint ,这三个实现类,分别对应于前面讲解链接器 Coyote 时, 提到的链接器支持的三种IO模型:NIO,NIO2,APR , Tomcat8.5版本中,默认采用的是 NioEndpoint。

3、ProtocolHandler : Coyote 协议接口,通过封装 Endpoint和Processor , 实现针对具体

协议的处理功能。Tomcat 按照协议和 IO 提供了6个实现类。

  • AJP协议:

1) AjpNioProtocol :采用NIO的IO模型。

2) AjpNio2Protocol:采用NIO2的IO模型。

3) AjpAprProtocol :采用APR的IO模型,需要依赖于APR库。

H- TTP协议:

1) Http11NioProtocol :采用NIO的IO模型,默认使用的协议(如果服务器没有安装

APR)。

2) Http11Nio2Protocol:采用NIO2的IO模型。

3) Http11AprProtocol :采用APR的IO模型,需要依赖于APR库。

三、 Tomcat专题 - Tomcat架构 - 启动流程 - 源码跟踪

1、tomcat 源码入口 类

目录: org.apache.catalina.startup.java

2、 tomcat 源码入口 main() 方法

MainClass:BootStrap ‐‐‐‐> main(String[] args)

java 复制代码
 /**
     * Main method and entry point when starting Tomcat via the provided
     * scripts.
     *
     * @param args Command line arguments to be processed
     */
    public static void main(String args[]) {

        System.out.println("main");

        if (daemon == null) {
            System.out.println("main if");
            // Don't set daemon until init() has completed
            Bootstrap bootstrap = new Bootstrap();
            try {
                bootstrap.init();
            } catch (Throwable t) {
                handleThrowable(t);
                t.printStackTrace();
                return;
            }
            daemon = bootstrap;
        } else {
            System.out.println("main else");
            // When running as a service the call to stop will be on a new
            // thread so make sure the correct class loader is used to prevent
            // a range of class not found exceptions.
            Thread.currentThread().setContextClassLoader(daemon.catalinaLoader);
        }

        try {
            String command = "start";
            if (args.length > 0) {
                command = args[args.length - 1];
            }

            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();
                if (null == daemon.getServer()) {
                    System.exit(1);
                }
            } 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);
        }

    }

四、 Tomcat专题 - Tomcat架构 - 启动流程 - 跟踪源码 - Debug

1、从启动流程图中以及源码中,我们可以看出Tomcat的启动过程非常标准化, 统一按照生命周期管理接口Lifecycle的定义进行启动。首先调用init() 方法进行组件的逐级初始化操作,然后再调用start()方法进行启动。

2、每一级的组件除了完成自身的处理外,还要负责调用子组件响应的生命周期管理方法, 组件与组件之间是松耦合的,因为我们可以很容易的通过配置文件进行修改和替换。

五、 Tomcat专题 - Tomcat架构 - 请求处理流程

1、 Tomcat 请求流程

1)设计了这么多层次的容器,Tomcat 是怎么确定每一个请求应该由哪个 Wrapper 容器里的 Servlet 来处理的呢?

答案是,Tomcat 是用 Mapper 组件来完成这个任务的。

2)Mapper 组件的功能就是将用户请求的 URL 定位到一个 Servlet,它的工作原理是:

Mapper 组件里保存了 Web 应用的配置信息,其实就是容器组件与访问路径的映射关系,

比如 Host 容器里配置的域名、Context 容器里的 Web 应用路径,以及 Wrapper 容器里

Servlet 映射的路径,你可以想象这些配置信息就是一个多层次的 Map。

3)当一个请求到来时,Mapper 组件通过解析请求 URL 里的域名和路径,再到自己保存的

Map 里去查找,就能定位到一个 Servlet。请你注意,一个请求URL最后只会定位到一个

Wrapper 容器,也就是一个 Servlet。

2、下面的示意图中 , 就描述了 当用户请求链接 http://www.itcast.cn/bbs/findAll

后, 是如何找到最终处理业务逻辑的 servlet 。

3、那上面这幅图只是描述了根据请求的URL如何查找到需要执行的Servlet , 那么下面我们

再来解析一下 , 从Tomcat的设计架构层面来分析Tomcat的请求处理。

4、步骤如下:

1) Connector组件Endpoint中的Acceptor监听客户端套接字连接并接收Socket。

  1. 将连接交给线程池Executor处理,开始执行请求响应任务。

  2. Processor组件读取消息报文,解析请求行、请求体、请求头,封装成Request对象。

  3. Mapper组件根据请求行的URL值和请求头的Host值匹配由哪个Host容器、Context容器、Wrapper容器处理请求。

  4. CoyoteAdaptor组件负责将Connector组件和Engine容器关联起来,把生成的Request对象和响应对象Response传递到Engine容器中,调用 Pipeline。

  5. Engine容器的管道开始处理,管道中包含若干个Valve、每个Valve负责部分处理逻辑。执行完Valve后会执行基础的 Valve--StandardEngineValve,负责调用Host容器的Pipeline。

  6. Host容器的管道开始处理,流程类似,最后执行 Context容器的Pipeline。

  7. Context容器的管道开始处理,流程类似,最后执行 Wrapper容器的Pipeline。

  8. Wrapper容器的管道开始处理,流程类似,最后执行 Wrapper容器对应的Servlet对象的 处理方法。

六、 Tomcat专题 - Tomcat架构 - 请求处理流程 - 源码跟踪

1、请求流程源码解析

2、在前面所讲解的Tomcat的整体架构中,我们发现Tomcat中的各个组件各司其职,组件之间松耦合,确保了整体架构的可伸缩性和可拓展性,那么在组件内部,如何增强组件的灵活性和拓展性呢?

在 Tomcat 中,每个 Container 组件采用责任链模式来完成具体的请求处理。

3、在 Tomcat 中定义了 Pipeline 和 Valve 两个接口,Pipeline 用于构建责任链, 后者代表责任链上的每个处理器。Pipeline 中维护了一个基础的Valve,它始终位于 Pipeline 的末端(最后执行),封装了具体的请求处理和输出响应的过程。

当然,我们也可以调用 addValve()方法, 为 Pipeline 添加其他的 Valve, 后添加的 Valve 位于基础的 Valve 之前,并按照添加顺序执行。Pipiline 通过获得首个Valve来启动整合链条的执行 。

上一节关联链接请点击
# 利刃出鞘_Tomcat 核心原理解析(二)

相关推荐
尢词13 小时前
SpringMVC
java·spring·java-ee·tomcat·maven
清风百草13 小时前
【04】【Maven项目热部署】将Maven项目热部署到远程tomcat服务器上
tomcat·maven项目热部署
蒋桐城1 天前
Tomcat 启动卡住,日志显示 At least one JAR was scanned for TLDs yet contained no TLDs.
java·tomcat
qiaosaifei1 天前
SpringBoot项目中替换指定版本的tomcat
spring boot·后端·tomcat
雷神乐乐1 天前
IDEA构建JavaWeb项目,并通过Tomcat成功运行
服务器·tomcat·javaweb
陈大爷(有低保)1 天前
数据库连接池JNDI
数据库·mysql·tomcat
笔墨登场说说2 天前
JDK 里面的线程池和Tomcat线程池的区别
java·servlet·tomcat
爱分享的淘金达人2 天前
25国考照片处理器使用流程图解❗
java·考研·spring·eclipse·tomcat
爱分享的淘金达人2 天前
2025年山东省考报名流程图解
java·考研·spring·eclipse·tomcat·流程图
弓弧名家_玄真君3 天前
mac 安装tomcat
java·macos·tomcat