Tomcat 启动流程与类加载机制
1. 引言
Tomcat 的启动不仅仅是简单的 java -jar
或 catalina.sh start
。
它背后包含 Bootstrap 启动器、Catalina 控制器、Server/Service/Connector/Container 初始化 等关键步骤。
另一方面,Tomcat 为了支持 热部署、不同应用间类隔离,设计了 破坏双亲委派机制的类加载模型,这是 Java Web 容器的核心机制。
本篇我们将从 启动流程 和 类加载机制 两方面,全面剖析 Tomcat 内核。
2. Tomcat 启动流程总览
Tomcat 的启动过程主要分为以下几个阶段:
-
Bootstrap 初始化
- 加载
catalina.properties
- 初始化 Tomcat 的类加载器体系
- 加载
-
Catalina 初始化
- 创建
Catalina
对象 - 解析
server.xml
配置文件
- 创建
-
Server 与 Service 构建
- 创建
StandardServer
- 创建
StandardService
,并绑定 Connector 与 Container
- 创建
-
启动 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();}
}
主要步骤:
-
init()
- 加载系统属性、解析配置文件
- 创建类加载器:
CatalinaClassLoader
-
start()
- 反射调用
org.apache.catalina.startup.Catalina
的load()
方法 - 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()
时:
- Server.start() → 启动所有 Service
- Service.start() → 启动 Connector 和 Container
- Connector.start() → 打开端口,开始监听 HTTP/AJP 请求
- 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 的类加载器层次:
- Bootstrap ClassLoader(JVM 内置,加载
rt.jar
等) - System ClassLoader(AppClassLoader)
- CommonClassLoader(加载
$CATALINA_HOME/lib
) - CatalinaClassLoader(加载 Tomcat 自身核心类)
- SharedClassLoader(应用共享类)
- WebAppClassLoader(应用私有类,加载
WEB-INF/classes
和WEB-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. 总结
在本篇中,我们详细剖析了:
-
启动流程
- Bootstrap 初始化 → Catalina 控制器 → Server/Service → Connector/Container
-
类加载机制
- 普通双亲委派 vs Tomcat 类加载模型
- WebAppClassLoader 打破双亲委派,保证应用隔离
-
应用价值
- 支持多应用隔离
- 支持热部署
- 保证公共 API 的统一性