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 的核心架构中,最常见的四个名称是 Server、Service、Connector 和 Container。

Server:代表整个 Tomcat

Server 是 server.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 自动配置完成。

参考资料

相关推荐
数据库小学妹7 小时前
国产数据库怎么选?兼容、迁移、核心案例与融合架构四道关
数据库·架构·国产数据库·数据库迁移·融合数据库
霸道流氓气质7 小时前
Serverless 架构入门与实战:FaaS/BaaS 模型、Spring Cloud Function 适配与 AI 推理冷启动优化的 Java 全栈指南
spring cloud·架构·serverless
数据技术说11 小时前
数据库缓存架构深度解析:命中率、一致性、多层缓存管理
数据库·架构
Ikalus198811 小时前
检查自己写着「这不会让任务失败」:一条 Critical 风险就这么过了 178 天
安全·架构
55873生态系统手记11 小时前
三足鼎立,文明永续:55873 全域文明生态系统的架构师分工、十三套子大典与 Web4 技术底座拆解
架构
姜鱼问生12 小时前
备份和服务器在同一台机器上,等于没备份
算法·架构
搜狐技术产品小编202312 小时前
MVI + Compose 架构实战:从状态混乱到单向数据流
架构
姜鱼问生12 小时前
别再 chmod 777 了,用 ACL 给它开一扇窗
后端·算法·架构
Dawson Zhu13 小时前
《Agentic Design Patterns》第 21 章导读:探索与发现
人工智能·语言模型·架构·aigc·agi
李福春13 小时前
技术思考问题6:技术演讲该晒成功架构,还是交代失败与取舍?
java·开发语言·架构·computer use·深圳同盟·腾讯云架构师技术同盟·反演思维