Tomcat 整体架构与启动流程:从 Server 到 Servlet 加载

刚接触 Java Web 时,我一直把 Tomcat 简单理解成"运行 Java 项目的服务器"。后来接触 Nginx、Apache HTTP Server,又看到 Tomcat 自己也能监听 8080 端口,几个概念很容易混在一起。

其实只要分清"谁负责接收请求"和"谁负责执行 Servlet",再顺着 Tomcat 的启动过程看一遍,它的整体结构并没有想象中复杂。

一、Tomcat、Apache 和 Nginx 有什么区别

这里所说的 Apache,一般是指 Apache HTTP Server,而不是整个 Apache 软件基金会。

Nginx 和 Apache HTTP Server 主要定位为 Web 服务器,擅长处理静态资源、反向代理、负载均衡和 HTTPS。Tomcat 则首先是一个 Servlet 容器,主要用于部署和运行 Java Web 应用。

简单对比如下:

对比项 Tomcat Nginx Apache HTTP Server
核心定位 Servlet 容器 Web 服务器、反向代理 Web 服务器
Java Servlet/JSP 原生支持 不直接支持 不直接支持
静态资源 可以处理,但不是主要优势 性能和并发能力较强 支持完善
反向代理 可以实现,但不常作为主要网关 非常常见 支持
常见场景 运行 Spring MVC、Servlet 应用 网关、负载均衡、静态资源 静态站点、模块化 Web 服务

Tomcat 本身也包含 HTTP Connector,所以它可以独立接收 HTTP 请求,并不是必须与 Nginx 搭配。开发环境中,我们直接访问 Spring Boot 的 8080 端口,本质上就是在访问内嵌 Tomcat。

生产环境经常采用下面的结构:

复制代码
浏览器 → Nginx → 多个 Tomcat 实例 → Java 应用

这样做并不是因为 Tomcat 无法提供 HTTP 服务,而是希望让 Nginx 负责域名、HTTPS、静态资源、限流和负载均衡,Tomcat 专心运行 Java 业务。

二、Tomcat 的启动过程

我们在 Linux 中通常执行:

复制代码
bin/startup.sh

Windows 中对应的是 startup.bat。脚本的主要作用是准备环境变量和 JVM 参数,随后调用 catalina.sh start,最终启动 Java 入口类:

复制代码
org.apache.catalina.startup.Bootstrap.main(args)

Tomcat 的启动过程可以概括为下面几步。

1. 脚本准备运行环境

2. Bootstrap 创建类加载器

3. Catalina 解析 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>

4. 初始化和启动各级组件

复制代码
启动脚本 → Bootstrap → Catalina → 解析 server.xml
        → 创建组件 → 初始化组件 → 启动组件 → 监听请求

三、Tomcat 的整体分层架构

Tomcat 的核心架构中,最常见的四个名称是 ServerServiceConnectorContainer

Server:代表整个 Tomcat

Serverserver.xml 的最外层元素,代表整个 Catalina Servlet 容器。一个 Tomcat 实例通常只有一个 Server,其中可以包含多个 Service。

Service:连接网络层和容器层

Service 不是直接处理业务的组件,它更像一个组合层:一个 Service 可以包含多个 Connector,但通常只关联一个 Engine。

例如 HTTP 端口 8080 和 HTTPS 端口 8443 可以使用两个 Connector,最后把请求交给同一个 Engine,这样两种入口可以共享同一批 Web 应用。

Connector:负责网络和协议

Connector 负责监听端口、接收连接、解析 HTTP 或 AJP 协议,并把网络请求转换成 Tomcat 内部能够处理的 Request。业务处理完成后,它还负责把 Response 写回客户端。

Connector 解决的是"请求怎么进来、响应怎么出去",并不负责判断最终调用哪个 Servlet。

Container:负责找到并执行 Servlet

Container 负责请求在 Servlet 容器内部的处理。它还可以继续分为四层:

复制代码
Engine
└── Host
    └── Context
        └── Wrapper
  • Engine:处理当前 Service 中所有 Connector 转交的请求;

  • Host:代表一个虚拟主机,例如 www.example.com

  • Context:代表一个 Web 应用,例如 /shop

  • Wrapper:代表一个具体 Servlet,例如 Spring MVC 的 DispatcherServlet

假设访问 http://localhost:8080/shop/order/list,Connector 先接收并解析请求,Engine 再找到 localhost 对应的 Host,Host 根据 /shop 找到 Context,最后由 Wrapper 调用对应的 Servlet。

可以把整体关系简单记为:Server 管整个 Tomcat,Service 组合入口与容器,Connector 处理网络,Container 执行业务请求。

四、load-on-startup 有什么作用

在传统 Java Web 项目的 web.xml 中,可以通过 <load-on-startup> 控制 Servlet 的创建时机:

复制代码
<servlet>
    <servlet-name>initServlet</servlet-name>
    <servlet-class>com.example.InitServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

如果配置的是非负整数,Tomcat 会在 Web 应用启动阶段创建 Servlet,并调用它的 init() 方法,而不是等第一次请求到来时才初始化。

多个 Servlet 都配置了 load-on-startup 时,数值较小的会优先加载。例如,值为 1 的 Servlet 通常早于值为 5 的 Servlet;相同数值之间的先后顺序不应依赖。如果配置负数或者没有配置,一般会在第一次请求匹配到该 Servlet 时再创建。

使用注解也能达到同样效果:

复制代码
@WebServlet(urlPatterns = "/init", loadOnStartup = 1)
public class InitServlet extends HttpServlet {
    @Override
    public void init() {
        System.out.println("应用启动时完成初始化");
    }
}

它常用于提前初始化必要资源,让第一次请求不用承担初始化耗时。不过,不建议把大量数据加载、长时间远程调用或者不稳定任务全部放进 init()。一旦初始化抛出异常,Servlet 可能不可用,甚至影响应用正常启动。

在 Spring Boot 项目中,我们很少直接配置 Servlet 的 load-on-startup,但它并没有消失。Spring MVC 的 DispatcherServlet 同样由 Servlet 容器管理,只是大部分注册工作由 Spring Boot 自动配置完成。

参考资料

相关推荐
阡陌数智1 小时前
高可用LLM服务架构:多模型聚合系统并发管控、限流熔断与降级容错实战
架构
weixin199701080161 小时前
[特殊字符]《二手ERP × 闲鱼消息驱动架构:正向+逆向交易消息如何驱动WMS出库与回传》(附Python源码)
开发语言·python·架构
Jay Kay1 小时前
深入理解 RDMA 内存管理:海思 HNS RoCE 架构中的 HEM 表与 MTR 表有什么区别?
服务器·网络·架构
鲸能云2 小时前
【智慧能源】源储调售一体化架构与 EMS 滚动调度算法实践 —— 工商业光储收益提升 22% 的技术拆解
算法·架构·能源
Swift社区2 小时前
鸿蒙 App 如何设计 Memory Center?一文讲透 Agent 的长期记忆架构
华为·架构·harmonyos
许彰午2 小时前
24-MyBatisHelper与autoCount
java·低代码·架构
小马过河R2 小时前
微信小程序自定义登录态维护:从入门到生产级落地
后端·微信小程序·小程序·架构·登录态
努力努力再努力wz2 小时前
【Redis入门系列】:从 RESP 协议到 redis-plus-plus:Redis 客户端编程与 C++ 接口设计
开发语言·数据库·c++·redis·分布式·缓存·架构
计算机学姐3 小时前
基于SpringBoot的高校爱心慈善管理系统
java·vue.js·spring boot·后端·spring·tomcat·mybatis