Tomcat 启动流程与类加载机制

在这里插入图片描述

1. 引言

Tomcat 的启动不仅仅是简单的 java -jarcatalina.sh start
它背后包含 Bootstrap 启动器、Catalina 控制器、Server/Service/Connector/Container 初始化 等关键步骤。

另一方面,Tomcat 为了支持 热部署、不同应用间类隔离,设计了 破坏双亲委派机制的类加载模型,这是 Java Web 容器的核心机制。

本篇我们将从 启动流程类加载机制 两方面,全面剖析 Tomcat 内核。


2. Tomcat 启动流程总览

Tomcat 的启动过程主要分为以下几个阶段:

  1. Bootstrap 初始化

    • 加载 catalina.properties
    • 初始化 Tomcat 的类加载器体系
  2. Catalina 初始化

    • 创建 Catalina 对象
    • 解析 server.xml 配置文件
  3. Server 与 Service 构建

    • 创建 StandardServer
    • 创建 StandardService,并绑定 Connector 与 Container
  4. 启动 Server

    • 调用 server.start()
    • 启动 Service → 启动 Connector(协议监听) & Container(加载 Web 应用)

👉 流程图:

Bootstrap↓
Catalina↓
Server (StandardServer)↓
Service (StandardService)↓
Connector + Container↓
应用可对外提供服务

3. 启动入口:Bootstrap

Tomcat 的入口类是 org.apache.catalina.startup.Bootstrap

public final class Bootstrap {public static void main(String[] args) {Bootstrap bootstrap = new Bootstrap();bootstrap.init();bootstrap.start();}
}

主要步骤:

  1. init()

    • 加载系统属性、解析配置文件
    • 创建类加载器:CatalinaClassLoader
  2. start()

    • 反射调用 org.apache.catalina.startup.Catalinaload() 方法
    • Catalina 进一步加载 server.xml 并初始化 Server

4. Catalina 控制器

org.apache.catalina.startup.Catalina 是 Tomcat 的 核心控制器,负责解析配置文件并启动 Server:

public void load() {Digester digester = createStartDigester(); // XML 解析器InputSource inputSource = getConfigFile("server.xml");digester.parse(inputSource); // 解析 server.xmlserver = (Server) digester.getRoot();
}
  • 使用 Digester(基于 SAX 的 XML 解析器)解析 server.xml
  • 创建 Server → Service → Connector/Container 的对象模型
  • 保存到内存,供后续启动调用

5. Server 与 Service 初始化

Tomcat 的核心组件是通过 server.xml 配置加载的:

<Server port="8005" shutdown="SHUTDOWN"><Service name="Catalina"><Connector port="8080" protocol="HTTP/1.1"/><Engine name="Catalina" defaultHost="localhost"><Host name="localhost" appBase="webapps"/></Engine></Service>
</Server>
  • Server:代表整个 Tomcat 实例
  • Service:将 Connector 和 Container 组合
  • Connector:监听端口、接收请求
  • Container:四层容器体系(Engine → Host → Context → Wrapper)

6. Server 启动流程

当调用 server.start() 时:

  1. Server.start() → 启动所有 Service
  2. Service.start() → 启动 Connector 和 Container
  3. Connector.start() → 打开端口,开始监听 HTTP/AJP 请求
  4. Container.start() → 加载 Web 应用,初始化 Servlet

源码片段:

public class StandardServer extends LifecycleBase {@Overrideprotected void startInternal() throws LifecycleException {for (Service service : services) {service.start(); // 启动 Service}}
}

7. Tomcat 的类加载机制

普通 Java 程序的类加载遵循 双亲委派机制

BootstrapClassLoader↓
ExtClassLoader↓
AppClassLoader↓
用户自定义类加载器

但是 Tomcat 必须满足:

  • 不同 Web 应用类相互隔离
  • 公共类(如 Servlet API)在所有应用共享
  • 支持热部署、重新加载

因此 Tomcat 打破了双亲委派,设计了 多层类加载器模型


8. Tomcat 类加载器体系

Tomcat 的类加载器层次:

  1. Bootstrap ClassLoader(JVM 内置,加载 rt.jar 等)
  2. System ClassLoader(AppClassLoader)
  3. CommonClassLoader(加载 $CATALINA_HOME/lib
  4. CatalinaClassLoader(加载 Tomcat 自身核心类)
  5. SharedClassLoader(应用共享类)
  6. WebAppClassLoader(应用私有类,加载 WEB-INF/classesWEB-INF/lib

👉 层次关系图:

BootstrapClassLoader↓
SystemClassLoader↓
CommonClassLoader├── CatalinaClassLoader (Tomcat 内部类)├── SharedClassLoader (共享库)└── WebAppClassLoader (应用隔离)

9. 破坏双亲委派的实现

Tomcat 的 WebAppClassLoaderBase 重写了 loadClass 方法:

@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {// 1. 先从缓存中找Class<?> clazz = findLoadedClass(name);if (clazz == null) {try {// 2. 先自己尝试加载clazz = findClass(name);} catch (ClassNotFoundException e) {// 3. 加载不到再交给父加载器clazz = super.loadClass(name, resolve);}}return clazz;
}

区别:

  • 普通类加载器:先父后子(双亲委派)
  • Tomcat WebAppClassLoader:先子后父(保证 Web 应用的私有类优先加载)

10. 类加载机制的应用场景

  • Servlet API:在 CommonClassLoader 中加载,供所有应用共享
  • 第三方依赖(例如 Spring Jar 包):放在 WEB-INF/lib,由 WebAppClassLoader 加载,避免冲突
  • 热部署:通过销毁并重建 WebAppClassLoader 实现

11. 总结

在本篇中,我们详细剖析了:

  1. 启动流程

    • Bootstrap 初始化 → Catalina 控制器 → Server/Service → Connector/Container
  2. 类加载机制

    • 普通双亲委派 vs Tomcat 类加载模型
    • WebAppClassLoader 打破双亲委派,保证应用隔离
  3. 应用价值

    • 支持多应用隔离
    • 支持热部署
    • 保证公共 API 的统一性

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/98105.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/98105.shtml
英文地址,请注明出处:http://en.pswp.cn/web/98105.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MTK Linux Charger驱动分析(十二)- mtk_pd_adapter.c

1. 代码整体分析 mtk_pd_adapter.c(源文件) 主要内容: 该文件实现了MediaTek平台的USB PD(Power Delivery)适配器驱动,基于Linux内核的电源管理和Type-C端口控制器(TCPC)框架。 它处理PD协议事件,包括PD连接状态、Type-C状态、水检测(WD_STATUS)、Sink VBUS变化等。…

Spring Boot Logback 日志配置详解:从基础到分布式追踪

日志是应用程序不可或缺的组成部分&#xff0c;它不仅能帮助我们调试问题&#xff0c;还能监控系统运行状态。在 Spring Boot 生态中&#xff0c;Logback 凭借其高性能和灵活性成为首选的日志框架。本文将通过一个实际的 Logback 配置文件&#xff0c;详细解析其各个组件的功能…

软件体系结构——后端三层架构

三层架构——Controller、Service、Dao 不仅是对代码进行的逻辑分层。其真正的本质&#xff0c;是将业务、技术和数据剥离。搞业务的专心做业务&#xff0c;搞技术的专心搞技术&#xff0c;做数据存储的专心做数据存储。三方通过接口进行对接&#xff0c;任一部分重构&#xff…

QML学习笔记(一)基本了解和工程配置

前言&#xff1a; 已经从事QT开发几年了&#xff0c;但对于QML这个东西始终是没有彻底掌握&#xff0c;一方面实际工作中没有用到过&#xff0c;其次它的语法对我来说是全新的东西&#xff0c;不像QWidget那一套可以直接在C中去写。这就是为什么网上都说qml更简单&#xff0c;我…

SAP HANA Scale-out 04:缓存

结果缓存静态结果缓存 Vs 动态结果缓存FeatureStatic Result CacheDynamic Result CacheTarget Scenario对复杂视图&#xff08;通常是顶层视图&#xff09;的查询频繁更新的大表&#xff08;例如ACDOCA&#xff09;上的聚合查询Query result非实时数据实时数据ScopeTarget obj…

嘉兴禾润 HTR7216 (S) LED 驱动芯片:特性与应用

在如今智能设备飞速普及的时代&#xff0c;无论是智能家居的氛围营造、IoT 设备的状态提示&#xff0c;还是个人消费电子的视觉呈现&#xff0c;都离不开高性能 LED 驱动芯片的支撑。嘉兴禾润推出的 HTR7216 (S) LED 驱动芯片&#xff0c;凭借丰富的功能、精准的控制以及出色的…

Python实现剑龙优化算法 (Stegosaurus Optimization Algorithm, SOA)优化函数(付完整代码)

Python实现剑龙优化算法 (Stegosaurus Optimization Algorithm, SOA)优化函数&#xff08;付完整代码&#xff09;1.剑龙优化算法介绍剑龙优化算法&#xff08;Stegosaurus Optimization Algorithm&#xff0c;SOA&#xff09;是一种受剑龙独特生理结构和行为模式启发而设计的元…

分布式拜占庭容错算法——权益证明(PoS)算法详解

Java 实现权益证明&#xff08;PoS&#xff09;算法详解 一、PoS 核心机制 #mermaid-svg-Sbj0HU6MjOl1yo5L {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-Sbj0HU6MjOl1yo5L .error-icon{fill:#552222;}#mermaid-s…

【论文阅读】谷歌:生成式数据优化,只需请求更好的数据

谷歌DeepMind团队通过Generative Data Refinement&#xff08;GDR&#xff09;技术&#xff0c;成功将极端有毒的4chan讨论数据转化为安全且语义丰富的训练素材&#xff0c;推动了LLM训练数据净化的新范式&#xff1a; • GDR利用预训练大模型对原始数据进行“重写”&#xff0…

C++ 多线程实战 10|C++20 的信号量、闩锁与屏障

目录 前言 学习目标 1. 信号量&#xff08;Semaphore&#xff09; 示例&#xff1a;限制并发下载任务 2. 闩锁&#xff08;Latch&#xff09; 示例&#xff1a;赛跑 3. 屏障&#xff08;Barrier&#xff09; 示例&#xff1a;图像处理流水线 4. 常见坑与对策 5. 实践作…

【Java SE】01. 初识Java

1. 认识Java Java是一种优秀的程序设计语言&#xff0c;它具有令人赏心悦目的语法和易于理解的语义。Java还是一个有一系列计算机软件和规范形成的技术体系&#xff0c;这个技术体系提供了完整的用于软件开发和跨平台部署的支持环境&#xff0c;并广泛应用于嵌入式系统、移动终…

解锁仓储智能调度、运输路径优化、数据实时追踪,全功能降本提效的智慧物流开源了

AI 视频监控平台&#xff1a;全链路协同驱动的智能监控解决方案AI 视频监控平台是一款融合高性能功能与轻量化操作的实时算法驱动型视频监控系统&#xff0c;其核心愿景在于深度破除不同芯片厂商间的技术壁垒&#xff0c;省去冗余重复的适配环节&#xff0c;最终达成芯片、算法…

冒泡排序与选择排序以及单链表与双链表

1. 冒泡排序&#xff08;Bubble Sort&#xff09; 1. 原理 冒泡排序是一种 简单的排序算法&#xff0c;通过 两两比较相邻元素&#xff0c;把较大的元素逐渐 “冒泡” 到数组末尾。 思路&#xff1a; 从数组头开始&#xff0c;比较相邻两个元素。 如果前一个比后一个大&…

Python实现计算点云投影面积

本次我们分享一种基于 Open3D 的快速、稳健方法&#xff0c;用于从激光点云中自动提取“地面”并计算其投影面积。算法先自适应估计地面高程&#xff0c;再将地面点投影至水平面&#xff0c;随后用凸包或最小外接矩形求取面积。整个流程无需人工干预&#xff0c;单文件即可运行…

AXI4 协议

一、AXI4简介AXI4&#xff08;Advanced eXtensible Interface 4&#xff09;是ARM公司推出的高性能片上总线协议&#xff0c;属于AMBA&#xff08;Advanced Microcontroller Bus Architecture&#xff09;标准的一部分。它专为高带宽、低延迟的片上通信设计&#xff0c;广泛应用…

《饿殍:明末千里行》Switch版试玩发布 3月13日发售

使用jQuery的常用方法与返回值分析 jQuery是一个轻量级的JavaScript库&#xff0c;旨在简化HTML文档遍历和操作、事件处理以及动画效果的创建。本文将介绍一些常用的jQuery方法及其返回值&#xff0c;帮助开发者更好地理解和运用这一强大的库。 1. 选择器方法 jQuery提供了多种…

[特殊字符] 认识用户手册用户手册(也称用户指南、产品手册)是通过对产品功能的清

一份优秀的用户手册能有效降低用户的使用门槛&#xff0c;提升用户体验和工作效率。下面我将为你梳理编写用户手册的核心要点、步骤和技巧。&#x1f4d6; 认识用户手册用户手册&#xff08;也称用户指南、产品手册&#xff09;是​​通过对产品功能的清晰解释&#xff0c;为特…

苹果软件代码混淆,iOS混淆、iOS加固、ipa安全与合规取证注意事项(实战指南)

在移动软件交付与合规审计中&#xff0c;苹果软件代码混淆已成为保护知识产权与用户数据的常规手段。但混淆带来的不仅是逆向难度的提升&#xff0c;也会触发崩溃取证、符号化&#xff08;symbolication&#xff09;、审计合规与法律证据保存等问题。本文从工程与合规双视角出发…

Redis框架详解

目录 1. redis是什么 主要特点 2. redis中存储的数据类型 2.1 String类型 2.2 List类型 2.3 Hash类型 2.4 Set类型 2.5 Zset类型 2.6 其它类型 3.redis高可用框架 1. redis是什么 Redis 是一个开源的、基于内存的数据结构存储系统&#xff0c;是 Remote Dictionary…