tomcat的启动流程及原理

2023-11-04

组件介绍:

Tomcat 最重要的是两个组件是:Connector(连接器) 和 Container(容器/集装箱),Connector 组件是可以被替换,这样可以提供给服务器设计者更多的选择,因为这个组件是如此重要,不仅跟服务器的设计的本身,而且和不同的应用场景也十分相关,所以一个 Container 可以选择对应多个 Connector。

多个 Connector 和一个 Container 就组成一个 Service,有了 Service 就可以对外提供服务了,但是 Service 还要一个生存的环境, Server 就提供了这样一个环境。所以整个 Tomcat 的生命周期由 Server 控制。

tomcat核心组件.JPG

下面来一层层的看,首先是Server,什么是server呢?

Server

Server 要完成的任务很简单,就是要能够提供一个接口让其它程序能够访问到 Service 集合,同时要维护它所包含的所有 Service 的生命周期,包括如何初始化如何结束服务如何找到别人要访问的 Service。还有一些次要的任务,如记录Service运行日志,维护Session等等。Server包含的组件结构如下:

tomcat-Server.png

Service

Service 是在 Connector 和 Container 外面多包一层,把它们组装在一起,向外面提供服务,一个 Service 可以设置多个 Connector,但是只能有一个 Container 容器。当然Service不仅仅包含这两个组件, Service 接口的方法列表如下:

tomcat-Service方法.png

Container

Container本意是集装箱的意思,是一个接口,定义了下属的各种容器,重要的是Wrapper、Host、Engine、Context等

tomcat-container结构.png

tomcat-container类图.png

Engine(引擎)

负责处理来自相关联的service的所有请求,处理后,将结果返回给service,而connector是作为service与engine的中间媒介出现的。
一个engine下可以配置一个默认主机,每个虚拟主机都有一个域名。当engine获得一个请求时,它把该请求匹配到虚拟主机(host)上,然后把请求交给该主机来处理。
Engine有一个默认主机,当请求无法匹配到任何一个虚拟主机时,将交给默认host来处理。Engine以线程的方式启动Host。

Host

代表一个虚拟主机,每个虚拟主机和某个网络域名(Domain Name)相匹配。
每个虚拟主机下都可以部署一个或多个web应用,每个web应用对应于一个context,有一个context path。
当Host获得一个请求时,将把该请求匹配到某个Context上,然后把该请求交给该Context来处理匹配的方法是“最长匹配”,所以一个path==””的Context将成为该Host的默认Context所有无法和其它Context的路径名匹配的请求都将最终和该默认Context匹配。

Context

一个Context对应于一个Web应用,一个Web应用由一个或者多个Servlet组成Context在创建的时候将根据配置文件$CATALINA_HOME/conf/web.xml$ WEBAPP_HOME/WEB-INF/web.xml载入Servlet类。当Context获得请求时,将在自己的映射表(mapping table)中寻找相匹配的Servlet类,如果找到,则执行该类,获得请求的回应,并返回。

Wrapper

Wrapper 代表一个 Servlet,它负责管理一个 Servlet,包括的 Servlet 的装载、初始化、执行以及资源回收。Wrapper 是最底层的容器,它没有子容器了,所以调用它的 addChild 将会报错。
Wrapper 的实现类是 StandardWrapper,StandardWrapper 还实现了拥有一个 Servlet 初始化信息的 ServletConfig,由此看出 StandardWrapper 将直接和 Servlet 的各种信息打交道。

Connector

Connector将在某个指定的端口上来监听客户的请求,把从socket传递过来的数据,封装成Request,传递给Engine来处理,并从Engine处获得响应并返回给客户。

Tomcat通常会用到两种Connector:

  1. Http Connector 在端口8080处侦听来自客户browser的http请求。 AJP Connector
  2. 在端口8009处侦听来自其它WebServer(Apache)的servlet/jsp代理请求。

Lifecycle

现实生活中大部分的事物都有生命周期,就像人的生老病死一样。

在编程中也有很多对象是具有生命周期的,从初始化、运行、回收等 会经历几个不同的阶段。 在tomcat中容器相关的好多组建都实现了Lifecycle接口,当tomcat启动时,其依赖的下层组件会全部进行初始化。 并且可以对每个组件生命周期中的事件添加监听器

例如当服务器启动的时候,tomcat需要去调用servlet的init方法和初始化容器等一系列操作,而停止的时候,也需要调用servlet的destory方法。而这些都是通过org.apache.catalina.Lifecycle接口来实现的。由这个类来制定各个组件生命周期的规范。

Lifecycle类图.png

tomcat生命周期类分析.png

LifecycleListener

在Lifecycle的介绍中提到,Lifecycle会对每个组件生命周期中的事件添加监听器,也就是addLifecycleListener(LifecycleListener listener)方法,而LifecycleListener就是上面提到的监听器。

LifecycleEvent

顾名思义,就是当有监听事件发生的时候,LifecycleEvent会存储时间类型和数据

/**
* Construct a new LifecycleEvent with the specified      parameters.
*
* @param lifecycle Component on which this event occurred
* @param type Event type (required)
* @param data Event data (if any)
*/
public LifecycleEvent(Lifecycle lifecycle, String type, Object data) {
   super(lifecycle);
   this.type = type;
   this.data = data;
}

tomcat 的启动过程

tomcat的启动的起点是Server.start()方法,在这里它会依次启动ContainerConnector相关组件,最后到达EndPoint(Tomcat启动的Socket管理者),完成整个启动过程。如下图是个简易过程:

tomcat启动流程.JPG

具体实现过程

StartFirst

/**
 * Start the server.
 *
 * @throws LifecycleException Start error
 */
public void start() throws LifecycleException {
    getServer();
    getConnector();
    server.start();
}

server启动之前需要准备好Server和Connector,server的默认实现是StandardServer, start()方法在其父类LifecycleBase中

tomcat-LifecycleBase的start方法.png

注:LifecycleBase还是StandardService, StandardEngine, StandardHost, StandardContext等的父类,所以当调用这些类的start()方法时其实都是调用此处的start()方法,而最重要的是在start()方法中会调用startInternal()startInternal()在LifecycleBase中是抽象方法,具体实现由各个实现类自己定义。

startServer

启动server其实就是启动service容器,靠StandardService中的startInternal()实现方法,参考代码如下:

tomcat-启动service容器.png

startService

启动service其实就是启动engine容器和connector容器,是在StandardEngine中实现的。参考代码如下:

tomcat-engine和connector容器准备.png

启动Engine

启动engine其实就是启动host容器(多线程),是在StandardHost中实现,参考代码如下:

tomcat-host容器准备.png

启动Host

启动Host的方式和上图一样,都是以线程的方式启动子Container,这里Host的children为Context

启动Context(上下文)

启动Wrapper

tomcat-启动Wrapper.png

loadServlet(加载servlet):

loadServlet1.png

loadServlet2.png

loadServlet3.png

它基本上描述了对 Servlet 的操作,当装载了 Servlet 后就会调用 Servlet 的init 方法,同时会传一个 StandardWrapperFacade对象给 Servlet,这个对象包装了 StandardWrapper,ServletConfig 与它们的关系图如下:

tomcat-ServletConfig类关系.png

启动Connector

Tomcat的Connector是Coyote connector的一种实现,这是tomcat的官方解释:The Coyote HTTP/1.1 Connector element represents a Connector component that supports the HTTP/1.1 protocol. It enables Catalina to function as a stand-alone web server, in addition to its ability to execute servlets and JSP pages.
Tomcat8之后默认使用nio作为接受请求策略,默认在Service启动的时候进行初始化,当然也可以单独启动,在默认的构造函数中会初始化ProtocolHandler

tomcat-connector构造.png

tomcat中支持两种协议的连接器:HTTP/1.1与AJP/1.3

HTTP/1.1协议负责建立HTTP连接,web应用通过浏览器访问tomcat服务器用的就是这个连接器,默认监听的是8080端口;

AJP/1.3协议负责和其他HTTP服务器建立连接,监听的是8009端口,比如tomcat和apache或者iis集成时需要用到这个连接器。

配置协议连机器.png

Connector的启动其实就是ProtocolHandler的启动,如下图:

connector启动.png

ProtocolHandler的类结构如下图:

ProtocolHandler的类结构.png

ConnectorstartInternal方法调用了ProtocolHandlestart方法,这个start方法就在AbstractProtocol中,如下图:

ProtocolHandle-start.png

EndPoint启动

EndPoint是tomcat启动的终点,EndPoint是Tomcat启动的Socket管理者(注:通过类图可以看出AbstractEndpoint已经脱离了Lifecycle和LifecycleListener体系,所以它只是一个简简单单的Socket管理者),因为是由他直接启动默认的Nio,在启动的时候先看看类结构图:

EndPoint类关系.png

EndPoint能做什么呢?来看一下他的方法:

EndPoint的方法.png


createAcceptorcreateExecutor等方法都是在初始化EndPoint很重要方法,因为在接收请求的时候,通过Acceptor的接收,经过重重模块,才能一路到达Servlet
那么EndPoint的启动,如下图:

tomcat-Endpoint启动.png


在这个地方会启动很多的线程,这些线程大多是用于tomcat接收请求的作用。关于tomcat的接收请求流程,后续会继续积累。

参考自:Tomcat的概念及启动原理浅析_sunyunjie361的博客-CSDN博客

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

tomcat的启动流程及原理 的相关文章

  • 定制法国号码格式

    我尝试为美国国家 地区使用自定义数字格式 到目前为止效果很好 Not something I want NumberFormat numberFormat0 NumberFormat getNumberInstance Locale US
  • 如何检测线程是否被IO阻塞?

    在Java中 线程可以有不同的状态 新的 可运行的 阻塞的 等待的 TIMED WAITING 的 终止的 然而 当线程被IO阻塞时 其状态为 RUNNABLE 如何判断是否被IO阻塞 NEW 线程已创建但尚未处理 可运行 线程正在占用CP
  • mvn dependency:analyze 结果不正确

    我一直在寻找一种工具 它能够向您显示未使用的依赖项 我很快就偶然发现了 Maven 命令mvn dependency analyze 这样做的问题是 它经常检测到 未使用的 依赖项 如果缺失 这些依赖项就会导致构建失败 这是优化项目的示例
  • 如何从 .t​​xt 文件读取数据并将数据放入对象的数组列表中?

    到目前为止 我所写的内容是基于我目前对基本数组的了解 但我只是不明白如何使用数组列表 或如何从文件中读取 到目前为止我所写的内容有效 任何有助于修复我的代码以从文件中读取并使用数组列表的链接或建议将不胜感激 谢谢 public class
  • java中如何围绕另一个移动对象旋转一个对象?

    我对 Java 很陌生 想要编写一个简单的太阳系统 其中月球绕地球旋转 地球绕太阳旋转 一切正常 除了月亮不想正确移动 由于地球偏离月球的初始位置 月球的自转半径会根据该距离而增大 同样 当地球接近月球惯性位置时 自转半径会减小 如果初始位
  • 如何在Spring Security SAML示例中配置IDP元数据和SP元数据?

    我想处理 Spring Security SAML 为此 我开始探索Spring安全SAML http docs spring io spring security saml docs 1 0 x reference html chapte
  • 带有 spring-kafka 的 Kafka 死信队列 (DLQ)

    最好的实施方式是什么死信队列 DLQ Spring Boot 2 0 应用程序中的概念 使用 spring kafka 2 1 x 来处理无法处理的所有消息 KafkaListener某些bean发送到某些预定义的Kafka DLQ主题的方
  • 在 Android 中使用 lambdaj

    有人尝试过在android开发中使用lambdaj库吗 当我创建一个简单的小型java应用程序时 它对我来说工作得很好 但我无法在android应用程序中使用它 UPDATE 我正在添加 lambdaj lambdaj 2 3 2 with
  • 按位非运算符

    为什么要按位运算 0 打印 1 在二进制中 不是0应该是1 为什么 你实际上很接近 在二进制中 不是0应该是1 是的 当我们谈论一位时 这是绝对正确的 然而 一个int其值为0的实际上是32位全零 将所有 32 个 0 反转为 32 个 1
  • 用java解密AES加密文件

    我有一个使用 AES 使用 java 应用程序加密的文件 我还有一个加密的密钥文件 但我不明白如何使用密钥来解密文件 大多数教程和示例都会在一个地方创建临时随机密钥 加密文件和解密 所以 问题是如何指定解密时必须使用的密钥 EDIT 我发现
  • 使用 javax.mail 和 CentOS 的邮件服务器

    我有一个 Java 程序 安装在一台旧的 Ubuntu 机器上 并使用 javax mail 发送邮件 然而 那台机器宕机了 我现在在新的 CentOS 机器上运行相同的 Java 应用程序 但是 当我尝试使用 mail smtp host
  • 从 Java 调用 Python 代码时出现问题(不使用 jython)

    我发现这是从 java 运行 使用 exec 方法 python 脚本的方法之一 我在 python 文件中有一个简单的打印语句 但是 我的程序在运行时什么也没做 它既不打印Python文件中编写的语句 也不抛出异常 程序什么都不做就终止了
  • 在Java中一个接一个地播放WAV文件

    我正在尝试玩几个WAV http en wikipedia org wiki WAV文件一个接一个 我尝试了这个方法 for String file audioFiles new AePlayWave file start 但这会同时播放它
  • JFreeChart MeterPlot

    我目前正在用java做Agent项目 在某些时候 我需要显示一个仪表 例如 电池电量 我的程序中有 5 个代理 每个代理都会创建自己的带有名称的仪表图 但不知何故他们没有更新数据集 或者他们正在更新数据集 只是它没有显示在仪表图上 任何想法
  • ObservableList 不更新 ArrayList

    对于学校作业 我们正在使用 JavaFX 中的 ObservableList 对象 对吗 我已经为此工作了一天多了 但无法弄清楚 老师只告诉我们 谷歌一下 所以这也没有帮助 基本上 我们正在开发一个基本的管理应用程序来跟踪人们及其家人 人们
  • 使用 Java 进行 AES 加密并使用 Javascript 进行解密

    我正在制作一个需要基于 Java 的 AES 加密和基于 JavaScript 的解密的应用程序 我使用以下代码作为基本形式进行加密 public class AESencrp private static final String ALG
  • 在调试模式下,哪些代码更改会自动反映在 Eclipse 中?

    我使用 eclipse 用于编写 调试 作为 IDE 在调试模式下 当我进行一些更改 例如初始化局部变量 时 它们会自动反映 但其他更改例如更改静态变量的值 有时我会收到一条消息 说我需要重新启动虚拟机 有时则不需要 现在的问题是哪些类型的
  • Spring Boot 健康执行器 - 什么时候上线?

    我找不到任何有关 Springs Health Actuator 何时返回 UP 状态的文档 你能依靠一切吗 Components正在初始化 会不会 Controller准备好满足请求了吗 为了测试应用程序上下文是否已加载 您可以执行此自定
  • 当我必须在 Netty4 编码器中调用 ByteBuf.retain() 时?

    我正在编写一个以 NUL 终止 JSON 消息的编码器 以便在消息碎片的情况下可以对其进行解码 我找到了这个样本 gt click https github com netty netty blob master codec src mai
  • PostgreSQL 使用 JPA 和 Hibernate 抛出“列的类型为 jsonb,但表达式的类型为 bytea”

    这是我的实体类 映射到表中postgres 9 4 我正在尝试将元数据存储为jsonb在数据库中输入 Entity Table name room categories TypeDef name jsonb typeClass JsonBi

随机推荐

  • [Python+Django]Web图书管理系统毕业设计之数据库及系统实现源码篇

    前排提醒 本文干货超多 为避免消化不良建议配合目录食用 本系列博文献给即将毕业的程序猿们 系列文章共三篇 在编写的过程中可以说几乎是参照毕业设计目录样式来进行的 相关图表和截图也都几乎按照毕业设计论文的要求来编制 完整阅读消化此系列博文套上
  • 人眼定位python代码_使用dlib,OpenCV和Python进行人脸识别—人眼眨眼检测

    前期文章我们分享了如何使用python与dlib来进行人脸识别 以及来进行人脸部分的识别 如下图 dlib人脸数据把人脸分成了68个数据点 从图片可以看出 人脸识别主要是识别 人眉 人眼 人鼻 人嘴以及人脸下颚边框 每个人脸的部位都有不同的
  • 百度营销:百度扩量投放技巧

    众所周知百度是国内大部分用户都在使用的搜索引擎 百度搜索投放的是关键词形式 今天将带来一些账户优化的建议 放量模式 共享预算有哪些投放细节呢 以下梳理了5个小技巧 1 适合的账户类型 更适合预算充足的广告主 如果当前 你每天的获客量远远满足
  • layui之ajax--回调函数

    问题 一个简单的AJAX提交表单操作 经常发生后台数据保存好了 前端layer弹出层没有关闭 父页面没有刷新 定位发现是回调函数没有执行 用Google Chrome浏览器这种现象较少 而Safari 和 firefox浏览器100 发生
  • 2021-02-09 链表复制

    给你一个长度为 n 的链表 每个节点包含一个额外增加的随机指针 random 该指针可以指向链表中的任何节点或空节点 构造这个链表的 深拷贝 深拷贝应该正好由 n 个 全新 节点组成 其中每个新节点的值都设为其对应的原节点的值 新节点的 n
  • mysql查看数据库状态

    很赞的文章 https codeplayer vip p j7sc4 官方教程是最应该查看的文档 https dev mysql com doc refman 5 5 en show html 我真正关心的数据 比如一秒钟到底能插入多少行数
  • Package javax.ws.rs

    http docs oracle com javaee 6 api javax ws rs package summary html Annotation Types Summary ApplicationPath Identifies t
  • 新路程------imx6的模块编译的Makefile

    KERNEL SOURCE opt IMX6 linux 3 0 35 obj m ldb o default make C KERNEL SOURCE M PWD modules arm hismall linux gcc pcf8563
  • python numpy从坐标序列中计算累计移动距离

    也是从其他程序中学习得到计算距离 position 通过list来存储坐标xy position append x y position np array position 转换成数组 dist arr np concatenate np
  • 基于docker一行命令搭建个人博客wordPress

    前言 作为对技术热爱的一群小伙伴们 技术分享开源社区的贡献都是我们技术人引以为傲的一件事情 不仅如此 技术分享或者记录也是对自己职业成长的记录 更甚者 如果你的技术分享深度不错 并且帮助到别人那么在面试中也是又很大帮助的 今天就给大家谈一下
  • 两条轨迹相似度算法,轨迹相似性度量

    百度地图 百度地图是百度提供的一项网络地图搜索服务 覆盖了国内近400个城市 数千个区县 在百度地图里 用户可以查询街道 商场 楼盘的地理位置 也可以找到离您最近的所有餐馆 学校 银行 公园等等 2010年8月26日 在使用百度地图服务时
  • VS2019环境下C++配置环境/创建动态链接库

    文章目录 前言 一 配置环境 0 准备 1 添加项目表 2 include文件与lib文件的配置 include文件设置 lib文件配置 二 使用已有代码生成动态链接库 前言 最近有一个收尾的项目分到了手里 由于基本没有使用过VS2019所
  • linux内核oops错误码说明,Linux Kernel Oops异常分析

    0 linux内核异常常用分析方法 异常地址是否在0附近 确认是否是空指针解引用问题 异常地址是否在iomem映射区 确认是否是设备访问总线异常问题 如PCI异常导致的地址访问异常 异常地址是否在stack附近 如果相邻 要考虑是否被踩 比
  • 验证尼科彻斯定理

    验证尼科彻斯定理 即 任何一个整数的立方都可以写成一串连续奇数的和 问题分析与算法设计 本题是一个定理 我们先来证明它是成立的 对于任一正整数a 不论a是奇数还是偶数 整数 a a a 1 必然为奇数 构造一个等差数列 数列的首项为 a a
  • SVN迁移至GIT,并附带历史提交记录

    文章目录 SVN代码同步至GIT 背景 准备工作 操作步骤 SVN代码同步至GIT 背景 近年随着信息工程的多元化发展 GIT逐渐取代SVN成为主流的版本管理工具 部门的项目代码也决定迁移至git进行管理 所以就调研了一下具体的实现方案 要
  • linux创建git仓库

    1 安装 yum install y git 2 查看 Git 版本 git version 3 查看有没有git用户 id git 没有用户创建 useradd git 设置密码 passwd git 删除密码 passwd d f gi
  • Tomcat配置远程调试端口

    1 Linxu系统 bin startup sh开始处中增加如下内容 Java代码 declare x CATALINA OPTS server Xdebug Xnoagent Djava compiler NONE Xrunjdwp tr
  • JVM系列-第10章-垃圾回收概述和相关算法

    文章目录 toc 垃圾回收概述 大厂面试题 蚂蚁金服 百度 天猫 滴滴 京东 阿里 字节跳动 什么是垃圾 为什么需要GC 早期垃圾回收 Java 垃圾回收机制 自动内存管理 应该关心哪些区域的回收 垃圾回收相关算法 标记阶段 引用计数算法
  • Python实现选择排序

    选择排序简介 选择排序 Selection sort 是一种简单直观的排序算法 简单来说就是从无序队列里面挑选最小的元素 和无序队列头部元素替换 放到有序队列中 最终全部元素形成一个有序的队列 选择排序原理 首先在未排序序列中找到最小 大
  • tomcat的启动流程及原理

    组件介绍 Tomcat 最重要的是两个组件是 Connector 连接器 和 Container 容器 集装箱 Connector 组件是可以被替换 这样可以提供给服务器设计者更多的选择 因为这个组件是如此重要 不仅跟服务器的设计的本身 而