一、Tomcat 是什么?

Tomcat,全称通常叫 Apache Tomcat,是 Java Web 开发中非常常见的服务器软件。

简单来说:

Tomcat 是一个用来运行 Java Web 程序的服务器。

当我们写 Java 后端项目时,比如写了一个接口:

@GetMapping("/hello")
public String hello() {
    return "Hello Tomcat";
}

然后在浏览器访问:

http://localhost:8080/hello

这个请求并不是直接被 Java 方法接收的。

中间需要有一个服务器来做这些事情:

1. 监听 8080 端口
2. 接收浏览器发来的 HTTP 请求
3. 解析请求路径 /hello
4. 找到对应的 Java 代码
5. 执行 Java 方法
6. 把返回结果封装成 HTTP 响应
7. 返回给浏览器

这个服务器就是 Tomcat。

所以 Tomcat 的核心作用可以概括为:

Tomcat 负责接收 HTTP 请求,并把请求交给 Java Web 程序处理,然后把处理结果返回给客户端。


二、为什么需要 Tomcat?

很多初学者会疑惑:

我不是已经写了 Java 代码吗?为什么还需要 Tomcat?

原因很简单:

普通 Java 程序一般是这样运行的:

public class Main {
    public static void main(String[] args) {
        System.out.println("Hello Java");
    }
}

这种程序从 main 方法开始执行,执行完就结束。

但是 Web 程序不一样。

Web 程序需要一直等待用户访问。

比如:

用户 A 访问 /login
用户 B 访问 /register
用户 C 访问 /student/list
用户 D 上传文件
用户 E 提交表单

这些请求可能随时到来。

所以 Web 程序需要一个长期运行的服务器。

这个服务器需要负责:

监听端口
接收请求
解析 HTTP
管理连接
调用 Java 代码
处理并发访问
返回响应结果

这就是 Tomcat 存在的原因。


三、Tomcat 在 Java Web 体系中的位置

Java Web 开发中经常出现这些东西:

名称 作用
JDK Java 开发和运行环境
Servlet Java Web 编程规范
JSP Java 服务端页面技术
Tomcat Servlet 容器 / Web 服务器
Maven 项目构建和依赖管理工具
Spring MVC Java Web MVC 框架
Spring Boot 快速开发 Spring 应用的框架
MySQL 数据库
浏览器 客户端

它们之间的关系大致如下:

flowchart LR
    A[浏览器] -->|HTTP 请求| B[Tomcat]
    B --> C[Servlet / Spring MVC]
    C --> D[Service 业务层]
    D --> E[DAO / Mapper 数据访问层]
    E --> F[MySQL 数据库]
    F --> E
    E --> D
    D --> C
    C --> B
    B -->|HTTP 响应| A

Tomcat 在其中处于非常关键的位置:

浏览器不是直接访问 Java 方法。
浏览器访问的是 Tomcat。
Tomcat 再把请求交给 Java Web 应用。

四、Tomcat 的本质:Web 服务器 + Servlet 容器

Tomcat 有两个非常重要的身份:

1. Web 服务器
2. Servlet 容器

1. Tomcat 作为 Web 服务器

作为 Web 服务器,Tomcat 可以做这些事:

监听端口
接收 HTTP 请求
返回 HTTP 响应
处理静态资源
管理连接

比如浏览器请求:

http://localhost:8080/index.html

Tomcat 可以返回一个 HTML 页面。

浏览器请求:

http://localhost:8080/img/logo.png

Tomcat 可以返回一张图片。

这就是 Web 服务器的职责。


2. Tomcat 作为 Servlet 容器

Tomcat 更重要的身份是:

Servlet 容器。

什么是 Servlet?

Servlet 是 Java Web 规范中的一种组件。

它可以接收请求并返回响应。

一个最原始的 Servlet 长这样:

import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;

public class HelloServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request,
                         HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("text/plain;charset=UTF-8");
        response.getWriter().write("Hello Tomcat");
    }
}

Servlet 本身不能直接运行,它需要一个容器来管理。

Tomcat 就是管理 Servlet 的容器。

Tomcat 会负责:

创建 Servlet 对象
初始化 Servlet
调用 Servlet 的 doGet/doPost 方法
销毁 Servlet
管理请求和响应对象
管理线程
管理 Web 应用生命周期

所以 Tomcat 也叫:

Servlet 容器
Web 容器
Java Web 容器

五、Tomcat、Servlet、Spring MVC 的关系

早期 Java Web 开发中,我们直接写 Servlet。

后来有了 Spring MVC,我们通常写 Controller。

比如:

@RestController
public class HelloController {

    @GetMapping("/hello")
    public String hello() {
        return "Hello Spring MVC";
    }
}

看起来我们没有写 Servlet。

但是底层仍然离不开 Servlet。

Spring MVC 的核心入口是:

DispatcherServlet

它本质上也是一个 Servlet。

请求流程大致是:

sequenceDiagram
    participant Browser as 浏览器
    participant Tomcat as Tomcat
    participant DispatcherServlet as DispatcherServlet
    participant Controller as Controller
    participant Service as Service
    participant DB as 数据库

    Browser->>Tomcat: 发送 HTTP 请求
    Tomcat->>DispatcherServlet: 转交请求
    DispatcherServlet->>Controller: 找到对应 Controller 方法
    Controller->>Service: 调用业务逻辑
    Service->>DB: 查询或修改数据
    DB-->>Service: 返回数据
    Service-->>Controller: 返回业务结果
    Controller-->>DispatcherServlet: 返回响应数据
    DispatcherServlet-->>Tomcat: 封装响应
    Tomcat-->>Browser: 返回 HTTP 响应

所以:

Spring MVC 不是替代 Tomcat。
Spring MVC 是运行在 Tomcat 里面的 Web 框架。
Tomcat 负责底层请求处理。
Spring MVC 负责更方便地组织 Controller、请求映射、参数绑定、响应返回。

六、Tomcat 和 Maven 的关系

Tomcat 和 Maven 不是同一种东西。

工具 作用
Maven 管理依赖、编译代码、打包项目
Tomcat 运行 Java Web 项目,处理 HTTP 请求

可以这样理解:

Maven 负责把项目“做出来”
Tomcat 负责把项目“跑起来”

比如传统 Web 项目中:

Maven 把项目打成 war 包
Tomcat 负责运行 war 包

流程:

flowchart TD
    A[Java Web 源代码] --> B[Maven 编译]
    B --> C[Maven 打包成 WAR]
    C --> D[部署到 Tomcat]
    D --> E[Tomcat 启动 Web 应用]
    E --> F[浏览器访问接口或页面]

在 Spring Boot 项目中,Tomcat 通常作为依赖被 Maven 引入。

例如:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

这个依赖里面默认包含:

Spring MVC
Jackson
Validation
内嵌 Tomcat

所以 Spring Boot 项目不需要你单独安装 Tomcat,也可以直接运行。


七、外部 Tomcat 和内嵌 Tomcat

Tomcat 有两种常见使用方式:

1. 外部 Tomcat
2. 内嵌 Tomcat

1. 外部 Tomcat

外部 Tomcat 是传统 Java Web 项目常见方式。

大致流程是:

1. 单独下载 Tomcat
2. 解压 Tomcat
3. 写 Java Web 项目
4. 使用 Maven 打成 war 包
5. 把 war 包放到 Tomcat 的 webapps 目录
6. 启动 Tomcat
7. 浏览器访问项目

示意图:

flowchart LR
    A[Java Web 项目] --> B[mvn package]
    B --> C[生成 xxx.war]
    C --> D[复制到 Tomcat/webapps]
    D --> E[启动外部 Tomcat]
    E --> F[浏览器访问]

外部 Tomcat 适合:

传统 Java Web 项目
老项目维护
学校早期 Java Web 实验
需要把多个 war 放在同一个 Tomcat 中运行的场景

2. 内嵌 Tomcat

Spring Boot 默认使用内嵌 Tomcat。

也就是说,Tomcat 被当成依赖打进了项目。

Spring Boot 项目启动时,Tomcat 会跟着一起启动。

启动类一般长这样:

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

启动后控制台经常可以看到:

Tomcat started on port 8080

这说明内嵌 Tomcat 已经启动了。

内嵌 Tomcat 的运行方式:

flowchart TD
    A[Spring Boot 项目] --> B[main 方法启动]
    B --> C[SpringApplication.run]
    C --> D[创建 Spring 容器]
    D --> E[启动内嵌 Tomcat]
    E --> F[监听 8080 端口]
    F --> G[接收浏览器请求]

内嵌 Tomcat 的优点:

不用单独安装 Tomcat
直接运行 main 方法
方便开发调试
方便部署
一个 jar 包就能运行
适合微服务和现代后端项目

3. 外部 Tomcat 和内嵌 Tomcat 对比

对比项 外部 Tomcat 内嵌 Tomcat
常见项目 传统 Java Web Spring Boot
是否单独安装 需要 不需要
打包方式 war jar
启动方式 启动 Tomcat java -jar xxx.jar
部署方式 war 放入 webapps 直接运行 jar
使用难度 稍复杂 简单
当前主流程度 老项目常见 新项目常见

八、Tomcat 安装目录结构详解

下载并解压 Tomcat 后,目录通常类似:

apache-tomcat
├── bin
├── conf
├── lib
├── logs
├── temp
├── webapps
└── work

每个目录的作用如下:

目录 作用
bin 存放启动、关闭 Tomcat 的脚本
conf 存放 Tomcat 配置文件
lib 存放 Tomcat 运行所需 jar 包
logs 存放日志文件
temp 存放临时文件
webapps 存放部署的 Web 项目
work 存放 JSP 编译后的文件和运行缓存

1. bin 目录

bin 目录中常见文件:

文件 作用
startup.bat Windows 启动 Tomcat
shutdown.bat Windows 关闭 Tomcat
startup.sh Linux/macOS 启动 Tomcat
shutdown.sh Linux/macOS 关闭 Tomcat
catalina.bat Windows 下 Tomcat 核心控制脚本
catalina.sh Linux/macOS 下 Tomcat 核心控制脚本

Windows 启动:

startup.bat

Linux/macOS 启动:

./startup.sh

关闭:

shutdown.bat

或者:

./shutdown.sh

2. conf 目录

conf 是 Tomcat 最重要的配置目录。

常见文件:

文件 作用
server.xml Tomcat 核心配置文件
web.xml 全局 Web 应用配置
context.xml 全局 Context 配置
tomcat-users.xml Tomcat 管理用户配置
logging.properties 日志配置
catalina.properties Catalina 相关属性配置

其中最重要的是:

server.xml

3. lib 目录

lib 目录中存放 Tomcat 自己运行需要的 jar 包。

比如:

servlet-api.jar
jsp-api.jar
el-api.jar
tomcat-coyote.jar
catalina.jar

这些 jar 是 Tomcat 自己的核心组件。

注意:

不建议随便往 Tomcat 的 lib 目录中丢业务 jar 包。

因为这样可能导致多个项目共享同一份 jar,容易引发版本冲突。


4. logs 目录

logs 存放 Tomcat 日志。

常见日志:

日志文件 作用
catalina.out Linux 下常见主日志
catalina.YYYY-MM-DD.log Catalina 日志
localhost.YYYY-MM-DD.log 本地应用日志
localhost_access_log.YYYY-MM-DD.txt 访问日志

开发中如果 Tomcat 启动失败,第一反应应该是:

看 logs 目录
看控制台错误

5. webapps 目录

webapps 是默认部署目录。

如果把一个 war 包放到这里:

webapps/student.war

启动 Tomcat 后,Tomcat 会自动解压成:

webapps/student/

然后可以访问:

http://localhost:8080/student

6. work 目录

work 目录主要存放 JSP 编译后的 Java 文件和 class 文件。

例如 JSP 页面:

index.jsp

Tomcat 会把它转换成 Servlet,再编译成 class。

这些中间文件就可能出现在 work 目录中。

如果 JSP 修改后不生效,有时可以清理 work 目录。


九、Tomcat 核心配置 server.xml

Tomcat 最核心的配置文件是:

conf/server.xml

其中有几个非常重要的概念:

Server
Service
Connector
Engine
Host
Context

它们的层级关系如下:

flowchart TD
    A[Server] --> B[Service]
    B --> C[Connector HTTP 8080]
    B --> D[Connector AJP 8009]
    B --> E[Engine]
    E --> F[Host localhost]
    F --> G[Context /app1]
    F --> H[Context /app2]

1. Server

Server 是 Tomcat 的最外层组件。

一个 Tomcat 实例对应一个 Server。

典型配置:

<Server port="8005" shutdown="SHUTDOWN">
    ...
</Server>

其中:

属性 作用
port="8005" 监听关闭命令的端口
shutdown="SHUTDOWN" 关闭命令字符串

注意:

8005 不是 Web 访问端口。
8080 才是默认 HTTP 访问端口。

2. Service

Service 把 Connector 和 Engine 连接起来。

典型配置:

<Service name="Catalina">
    ...
</Service>

可以理解为:

Service = 一组连接器 Connector + 一个处理引擎 Engine

3. Connector

Connector 负责接收客户端连接。

最常见的是 HTTP Connector:

<Connector port="8080"
           protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="8443" />

含义:

属性 作用
port="8080" Tomcat HTTP 访问端口
protocol="HTTP/1.1" 使用 HTTP/1.1 协议
connectionTimeout="20000" 连接超时时间,单位毫秒
redirectPort="8443" HTTPS 重定向端口

如果你想把 Tomcat 默认端口从 8080 改成 8081,就改这里:

<Connector port="8081"
           protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="8443" />

然后访问:

http://localhost:8081

4. Engine

Engine 是请求处理引擎。

典型配置:

<Engine name="Catalina" defaultHost="localhost">
    ...
</Engine>

含义:

属性 作用
name="Catalina" 引擎名称
defaultHost="localhost" 默认虚拟主机

5. Host

Host 表示虚拟主机。

典型配置:

<Host name="localhost"
      appBase="webapps"
      unpackWARs="true"
      autoDeploy="true">
</Host>

含义:

属性 作用
name="localhost" 主机名
appBase="webapps" Web 应用部署目录
unpackWARs="true" 是否自动解压 war 包
autoDeploy="true" 是否自动部署

所以默认情况下,把 war 包放到 webapps 目录,Tomcat 会自动部署。


6. Context

Context 表示一个具体的 Web 应用。

比如:

<Context path="/student" docBase="D:/apps/student" />

含义:

属性 作用
path="/student" 访问路径
docBase="D:/apps/student" 项目实际路径

访问地址:

http://localhost:8080/student

不过实际开发中,不太建议直接在 server.xml 中频繁配置 Context。

更推荐使用:

独立 Context 配置文件
IDEA 部署配置
Spring Boot 内嵌 Tomcat 配置

十、Tomcat 请求处理流程

当浏览器访问:

http://localhost:8080/student/list

Tomcat 内部大致流程如下:

flowchart TD
    A[浏览器发送 HTTP 请求] --> B[Connector 接收请求]
    B --> C[解析 HTTP 请求]
    C --> D[根据 Host 找到虚拟主机]
    D --> E[根据 Context Path 找到 Web 应用]
    E --> F[根据 URL Mapping 找到 Servlet]
    F --> G[调用 Servlet service 方法]
    G --> H[执行 doGet/doPost]
    H --> I[生成响应内容]
    I --> J[Connector 返回 HTTP 响应]
    J --> K[浏览器显示结果]

更直白地说:

Connector 管连接
Engine 管处理
Host 管虚拟主机
Context 管具体应用
Servlet 管具体业务入口

十一、Servlet 生命周期

Tomcat 作为 Servlet 容器,负责管理 Servlet 生命周期。

Servlet 生命周期包括:

1. 加载和实例化
2. 初始化 init()
3. 处理请求 service()
4. 销毁 destroy()

流程图:

flowchart TD
    A[Tomcat 启动或首次请求] --> B[加载 Servlet 类]
    B --> C[创建 Servlet 对象]
    C --> D[调用 init 方法]
    D --> E[等待请求]
    E --> F[请求到达]
    F --> G[调用 service 方法]
    G --> H{请求方法}
    H -->|GET| I[doGet]
    H -->|POST| J[doPost]
    I --> E
    J --> E
    E --> K[Tomcat 关闭]
    K --> L[调用 destroy 方法]

对应代码:

public class HelloServlet extends HttpServlet {

    @Override
    public void init() {
        System.out.println("Servlet 初始化");
    }

    @Override
    protected void doGet(HttpServletRequest request,
                         HttpServletResponse response) {
        System.out.println("处理 GET 请求");
    }

    @Override
    public void destroy() {
        System.out.println("Servlet 销毁");
    }
}

需要注意:

Servlet 默认通常是单例的。
多个请求可能由多个线程同时访问同一个 Servlet 对象。
所以 Servlet 中不要随便定义可变成员变量保存用户请求数据。

十二、Tomcat 中的 web.xml

传统 Java Web 项目中,web.xml 是非常重要的配置文件。

位置通常是:

src/main/webapp/WEB-INF/web.xml

它可以配置:

Servlet
Filter
Listener
欢迎页
错误页
Session 超时时间
MIME 类型

1. 配置 Servlet

传统写法:

<web-app>
    <servlet>
        <servlet-name>helloServlet</servlet-name>
        <servlet-class>com.example.HelloServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>helloServlet</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>
</web-app>

意思是:

访问 /hello 时,Tomcat 调用 com.example.HelloServlet。

2. 配置欢迎页

<welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.jsp</welcome-file>
</welcome-file-list>

访问:

http://localhost:8080/app/

Tomcat 会自动找:

index.html
index.jsp

3. 配置 Session 超时时间

<session-config>
    <session-timeout>30</session-timeout>
</session-config>

表示 Session 30 分钟超时。


十三、Tomcat、Filter、Listener

Java Web 中除了 Servlet,还有 Filter 和 Listener。


1. Filter 过滤器

Filter 可以在请求进入 Servlet 前后进行处理。

常见用途:

登录校验
权限控制
编码处理
日志记录
跨域处理
敏感词过滤

流程图:

flowchart LR
    A[浏览器请求] --> B[Filter 1]
    B --> C[Filter 2]
    C --> D[Servlet / Controller]
    D --> E[Filter 2 响应处理]
    E --> F[Filter 1 响应处理]
    F --> G[返回浏览器]

示例代码:

public class LoginFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request,
                         ServletResponse response,
                         FilterChain chain) {

        // 请求进入 Servlet 前处理

        // 放行
        chain.doFilter(request, response);

        // 响应返回浏览器前处理
    }
}

2. Listener 监听器

Listener 用来监听 Web 应用中的事件。

常见监听对象:

ServletContext
HttpSession
ServletRequest

常见用途:

项目启动时初始化资源
统计在线人数
监听 Session 创建和销毁
加载配置文件

示例:

public class MyListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("Web 应用启动");
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("Web 应用关闭");
    }
}

十四、Tomcat 的端口

Tomcat 中常见端口:

端口 作用
8080 HTTP 访问端口
8005 关闭 Tomcat 的端口
8009 AJP 协议端口
8443 HTTPS 重定向端口

最常见的是:

8080

如果启动 Tomcat 报错:

Address already in use

通常说明端口被占用了。

解决方法:

1. 关闭占用端口的程序
2. 修改 Tomcat 端口

Windows 查看端口占用:

netstat -ano | findstr 8080

找到 PID 后结束进程:

taskkill /PID 进程号 /F

或者修改 server.xml

<Connector port="8081" protocol="HTTP/1.1" />

十五、Tomcat 部署方式

Tomcat 常见部署方式有几种:

1. 直接把项目目录放到 webapps
2. 把 war 包放到 webapps
3. 在 server.xml 中配置 Context
4. 在 conf/Catalina/localhost 下配置 Context
5. IDEA 中配置 Tomcat 部署
6. Spring Boot 内嵌 Tomcat 直接运行 jar

1. war 包部署

假设项目打包后生成:

student.war

复制到:

Tomcat/webapps/student.war

启动 Tomcat 后,会自动解压:

Tomcat/webapps/student/

访问:

http://localhost:8080/student

2. ROOT 项目部署

如果希望访问:

http://localhost:8080/

直接进入你的项目,而不是:

http://localhost:8080/student

可以把项目命名为:

ROOT.war

部署后访问根路径即可。


3. IDEA 中部署 Tomcat

在 IDEA 中配置外部 Tomcat,大致流程是:

1. 下载并解压 Tomcat
2. IDEA 中配置 Application Server
3. 添加 Tomcat Server
4. 选择 Local
5. 配置 Deployment
6. 添加 war exploded 或 war
7. 启动 Tomcat

常见部署形式:

类型 含义
war 打成 war 包部署
war exploded 解压目录形式部署,开发调试更方便

开发阶段通常选择:

war exploded

十六、Tomcat 和 Spring Boot 配置端口

传统外部 Tomcat 修改端口:

conf/server.xml

修改:

<Connector port="8080" protocol="HTTP/1.1" />

Spring Boot 内嵌 Tomcat 修改端口:

server:
  port: 8081

或者 application.properties

server.port=8081

启动后访问:

http://localhost:8081

十七、Spring Boot 中切换 Tomcat

Spring Boot 默认使用 Tomcat。

但是也可以换成 Jetty 或 Undertow。

例如排除 Tomcat,使用 Jetty:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </exclusion>
    </exclusions>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jetty</artifactId>
</dependency>

这说明:

Tomcat 不是 Spring Boot 唯一选择。
只是 Spring Boot Web 默认使用 Tomcat。

十八、Tomcat 类加载机制简单理解

Tomcat 会运行多个 Web 应用。

为了避免应用之间互相干扰,Tomcat 有自己的类加载机制。

常见类加载层级可以简化理解为:

Bootstrap ClassLoader
    ↓
System ClassLoader
    ↓
Common ClassLoader
    ↓
Webapp ClassLoader

示意图:

flowchart TD
    A[Bootstrap ClassLoader<br/>加载 JDK 核心类] --> B[System ClassLoader<br/>加载系统类路径]
    B --> C[Common ClassLoader<br/>加载 Tomcat/lib 中公共类]
    C --> D[Webapp ClassLoader A<br/>加载应用 A 的 WEB-INF/lib 和 classes]
    C --> E[Webapp ClassLoader B<br/>加载应用 B 的 WEB-INF/lib 和 classes]

每个 Web 应用通常有自己的 Webapp ClassLoader。

这带来的好处是:

不同 Web 应用可以使用不同版本的 jar 包。
应用 A 的类一般不会直接污染应用 B。

但是也要注意:

不要随便把业务 jar 放到 Tomcat/lib。
否则可能导致所有 Web 应用共享同一个 jar,引发版本冲突。

十九、Tomcat 的线程模型简单理解

Tomcat 是服务器,需要同时处理很多请求。

不可能一个请求一个进程。

Tomcat 通常使用线程池处理请求。

简化流程:

flowchart TD
    A[客户端请求] --> B[Tomcat Connector]
    B --> C[请求队列]
    C --> D[线程池]
    D --> E[工作线程 1]
    D --> F[工作线程 2]
    D --> G[工作线程 3]
    E --> H[调用 Servlet/Controller]
    F --> H
    G --> H

也就是说:

Tomcat 接收到请求后,会从线程池中取一个线程来处理。

这就是为什么后端代码要注意线程安全。

比如 Servlet 或 Controller 中不要这样写:

@RestController
public class UserController {

    private String username;

    @GetMapping("/set")
    public String set(String name) {
        this.username = name;
        return username;
    }
}

因为多个请求可能同时访问同一个 Controller 对象,成员变量可能互相覆盖。

应该使用局部变量:

@GetMapping("/set")
public String set(String name) {
    String username = name;
    return username;
}

二十、Tomcat 常见性能配置

Tomcat 性能配置通常在 server.xml 的 Connector 上调整。

示例:

<Connector port="8080"
           protocol="HTTP/1.1"
           maxThreads="200"
           minSpareThreads="10"
           acceptCount="100"
           connectionTimeout="20000"
           maxConnections="8192" />

常见参数:

参数 作用
maxThreads 最大工作线程数
minSpareThreads 最小空闲线程数
acceptCount 请求等待队列长度
connectionTimeout 连接超时时间
maxConnections 最大连接数

简单理解:

maxThreads 决定最多同时有多少线程处理请求。
acceptCount 决定线程都忙时,最多有多少请求排队等待。
connectionTimeout 决定连接多久没响应就超时。

注意:

这些参数不是越大越好,要结合 CPU、内存、业务耗时、数据库能力综合设置。

如果 maxThreads 设置太大,可能导致:

线程切换成本升高
内存占用增加
数据库压力变大
系统反而更慢

二十一、Tomcat 常见日志

Tomcat 排查问题时,日志非常重要。

常见日志目录:

Tomcat/logs

常见日志:

日志 作用
catalina.out Linux 下常见主日志
catalina.YYYY-MM-DD.log Tomcat 核心日志
localhost.YYYY-MM-DD.log Web 应用相关日志
localhost_access_log.YYYY-MM-DD.txt HTTP 访问日志
manager.YYYY-MM-DD.log Manager 应用日志
host-manager.YYYY-MM-DD.log Host Manager 应用日志

启动失败时优先看:

控制台输出
logs/catalina 日志
logs/localhost 日志

二十二、Tomcat 常见问题与解决方法

1. 端口 8080 被占用

错误现象:

Address already in use
Port 8080 was already in use

原因:

8080 端口已经被其他程序占用。

Windows 查看:

netstat -ano | findstr 8080

结束进程:

taskkill /PID 进程号 /F

或者修改 Tomcat 端口:

<Connector port="8081" protocol="HTTP/1.1" />

2. Tomcat 启动乱码

原因可能是控制台编码不一致。

解决方式之一是在 IDEA 或启动参数中配置 UTF-8。

Spring Boot 中也可以配置:

server.servlet.encoding.charset=UTF-8
server.servlet.encoding.enabled=true
server.servlet.encoding.force=true

3. 访问 404

404 表示资源不存在。

常见原因:

1. 项目没有部署成功
2. 访问路径写错
3. Context Path 不对
4. Controller 映射路径不对
5. war 包名称和访问路径不一致
6. 静态资源位置不正确

例如部署的是:

student.war

访问路径通常是:

http://localhost:8080/student

而不是:

http://localhost:8080/

除非部署为:

ROOT.war

4. 访问 500

500 表示服务器内部错误。

一般说明:

请求已经进入后端程序,但程序运行出错。

常见原因:

空指针异常
数据库连接失败
SQL 报错
依赖缺失
配置文件错误
业务代码异常

解决方法:

看控制台异常栈
看 Tomcat logs
定位 Caused by

5. 项目部署后不生效

常见原因:

1. 旧项目缓存未清理
2. war 没有重新部署
3. work 目录缓存
4. IDEA 没重新构建
5. 浏览器缓存

可尝试:

清理 target
重新 package
删除 webapps 下旧目录
删除 work 目录
重启 Tomcat
刷新浏览器缓存

6. ClassNotFoundException

错误:

ClassNotFoundException

说明某个类找不到。

常见原因:

1. jar 包没有放进去
2. Maven 依赖没有打包
3. scope 配置错误
4. Tomcat/lib 与项目 WEB-INF/lib 冲突
5. JDK 或 Tomcat 版本不兼容

7. UnsupportedClassVersionError

错误类似:

UnsupportedClassVersionError

原因:

编译项目使用的 JDK 版本高于运行 Tomcat 使用的 JDK 版本。

例如:

项目用 JDK 24 编译
Tomcat 实际运行在 JDK 17

解决:

1. 统一编译 JDK 和运行 JDK
2. 降低项目 target 版本
3. 修改 JAVA_HOME
4. 检查 Tomcat 启动脚本实际使用的 Java

检查:

java -version

二十三、Tomcat 和 JDK 版本关系

Tomcat 是 Java 程序,所以运行 Tomcat 必须有 JDK 或 JRE。

要注意:

Tomcat 版本和 JDK 版本需要兼容。

如果 Tomcat 版本太新,而 JDK 太旧,可能启动失败。

如果项目使用高版本 Java 编译,而 Tomcat 使用低版本 Java 运行,也可能失败。

最常见问题:

编译用 Java 17
运行用 Java 8
结果报 UnsupportedClassVersionError

所以要确保:

IDEA 项目 JDK
Maven 编译 JDK
Tomcat 运行 JDK
服务器 JAVA_HOME

尽量保持一致。


二十四、Tomcat 和 Servlet 规范版本关系

Tomcat 实现的是 Servlet 规范。

不同 Tomcat 版本支持不同的 Servlet 规范。

这里要特别注意一个重要变化:

Tomcat 9 及以前主要使用 javax.servlet 包名。
Tomcat 10 开始使用 jakarta.servlet 包名。

也就是说:

Tomcat 9 常见代码:

import javax.servlet.http.HttpServlet;

Tomcat 10 常见代码:

import jakarta.servlet.http.HttpServlet;

如果项目用的是 javax.servlet,却部署到 Tomcat 10,可能会出现兼容问题。

如果项目用的是 jakarta.servlet,却部署到旧 Tomcat,也可能出问题。

简单记忆:

老项目:javax.servlet,通常对应 Tomcat 9 或更早
新项目:jakarta.servlet,通常对应 Tomcat 10 或之后

Spring Boot 2 常见是 javax 体系。

Spring Boot 3 常见是 jakarta 体系。


二十五、Tomcat 与 Nginx 的区别

Tomcat 和 Nginx 都可以作为服务器,但侧重点不同。

对比 Tomcat Nginx
类型 Java Web 容器 高性能 Web 服务器 / 反向代理
主要用途 运行 Java Web 应用 静态资源、反向代理、负载均衡
是否运行 Servlet
是否适合处理静态资源 可以,但不是最强项 非常适合
常见组合 Tomcat 跑后端 Nginx 做入口

常见部署架构:

flowchart LR
    A[用户浏览器] --> B[Nginx]
    B --> C[静态资源 HTML/CSS/JS]
    B --> D[Tomcat 1]
    B --> E[Tomcat 2]
    D --> F[Java 后端应用]
    E --> G[Java 后端应用]

Nginx 常做:

反向代理
负载均衡
HTTPS 证书配置
静态资源服务
请求转发
限流

Tomcat 常做:

运行 Java Web 程序
处理 Servlet / Spring MVC 请求
执行业务逻辑

简单说:

Nginx 更像门卫和前台。
Tomcat 更像真正处理 Java 业务的办公室。

二十六、Tomcat 与 Spring Boot 的关系

Spring Boot 默认内嵌 Tomcat。

也就是说,Spring Boot 项目启动时,会自动启动 Tomcat。

传统 Tomcat 项目:

先启动 Tomcat
Tomcat 加载 Web 应用

Spring Boot 项目:

先启动 Spring Boot main 方法
Spring Boot 创建并启动内嵌 Tomcat

对比:

flowchart TD
    A[传统 Java Web] --> B[启动外部 Tomcat]
    B --> C[Tomcat 加载 war]
    C --> D[运行 Web 应用]

    E[Spring Boot] --> F[运行 main 方法]
    F --> G[启动 Spring 容器]
    G --> H[启动内嵌 Tomcat]
    H --> I[运行 Web 应用]

所以 Spring Boot 的便捷之处在于:

不需要单独安装 Tomcat
不需要手动部署 war
直接运行 jar 即可

二十七、Tomcat 常用面试题

1. Tomcat 是什么?

Tomcat 是一个开源的 Java Web 服务器,同时也是 Servlet 容器。它可以接收 HTTP 请求,运行 Servlet、JSP、Spring MVC 等 Java Web 应用,并将处理结果返回给客户端。


2. Tomcat 的核心作用是什么?

Tomcat 的核心作用包括:

监听端口
接收 HTTP 请求
解析请求
管理 Servlet 生命周期
调用 Java Web 程序
返回 HTTP 响应
部署和管理 Web 应用

3. Tomcat 是 Web 服务器还是应用服务器?

Tomcat 通常被称为:

Web 服务器
Servlet 容器
轻量级应用服务器

严格来说,Tomcat 主要实现 Servlet、JSP 等 Web 相关规范,不是完整的 Java EE 应用服务器。

完整 Java EE 应用服务器还可能支持:

EJB
JMS
JTA
完整 Jakarta EE 规范

所以 Tomcat 更准确地说是:

Servlet 容器 / Web 容器。


4. Tomcat 和 Servlet 的关系是什么?

Servlet 是 Java Web 规范中的组件。

Tomcat 是 Servlet 容器。

Tomcat 负责创建 Servlet、初始化 Servlet、调用 Servlet 的 service 方法、销毁 Servlet。


5. Tomcat 请求处理流程是什么?

简化流程:

浏览器发送请求
Connector 接收请求
Tomcat 根据 Host 和 Context 找到 Web 应用
根据 URL Mapping 找到 Servlet
调用 Servlet 的 service 方法
Servlet 处理请求
Tomcat 返回响应

6. Tomcat 默认端口有哪些?

常见端口:

8080:HTTP 访问端口
8005:关闭端口
8009:AJP 端口
8443:HTTPS 重定向端口

7. Tomcat 404 和 500 有什么区别?

404:

资源不存在,可能是路径错误、项目没部署、接口路径不对。

500:

服务器内部错误,通常是后端代码异常或配置异常。

8. 外部 Tomcat 和内嵌 Tomcat 有什么区别?

外部 Tomcat:

单独安装 Tomcat
项目通常打成 war 包部署
传统 Java Web 项目常见

内嵌 Tomcat:

Tomcat 作为依赖包含在项目中
Spring Boot 默认使用
项目通常打成 jar 包直接运行

9. Tomcat 9 和 Tomcat 10 的主要区别是什么?

一个非常重要的区别是包名变化:

Tomcat 9 及以前:javax.servlet
Tomcat 10 及以后:jakarta.servlet

因此老项目迁移到 Tomcat 10 时,可能需要处理 javaxjakarta 的兼容问题。


10. Tomcat 为什么要使用线程池?

因为服务器需要同时处理多个客户端请求。

如果每个请求都新建线程,成本很高。

Tomcat 使用线程池可以:

复用线程
降低创建销毁线程的开销
提高并发处理能力
控制最大并发线程数
避免资源被无限消耗

二十八、Tomcat 学习路线

如果你是 Java Web 初学者,可以按照这个顺序学习 Tomcat:

第一阶段:理解 Tomcat 是什么
第二阶段:理解 HTTP 请求和响应
第三阶段:理解 Servlet
第四阶段:会安装和启动 Tomcat
第五阶段:会修改端口
第六阶段:会部署 war 包
第七阶段:理解 webapps、conf、logs 目录
第八阶段:理解 server.xml
第九阶段:理解 Servlet 生命周期
第十阶段:理解 Filter 和 Listener
第十一阶段:理解 Tomcat 和 Spring MVC 的关系
第十二阶段:理解外部 Tomcat 和内嵌 Tomcat
第十三阶段:理解 Tomcat 和 Spring Boot 的关系
第十四阶段:掌握常见报错排查
第十五阶段:理解简单性能配置和线程模型

学习路线图:

flowchart TD
    A[认识 Tomcat] --> B[理解 HTTP 请求响应]
    B --> C[学习 Servlet]
    C --> D[安装和启动 Tomcat]
    D --> E[部署 Web 项目]
    E --> F[理解 webapps/conf/logs]
    F --> G[学习 server.xml]
    G --> H[理解 Servlet 生命周期]
    H --> I[学习 Filter 和 Listener]
    I --> J[理解 Spring MVC]
    J --> K[理解 Spring Boot 内嵌 Tomcat]
    K --> L[排查 404/500/端口占用]
    L --> M[理解线程池和性能配置]

二十九、Tomcat 初学者最应该记住的知识点

1. Tomcat 是运行 Java Web 项目的服务器。
2. Tomcat 既是 Web 服务器,也是 Servlet 容器。
3. 浏览器请求先到 Tomcat,再由 Tomcat 转给 Java Web 应用。
4. Servlet 不能自己运行,需要 Tomcat 这样的容器管理。
5. Spring MVC 的核心 DispatcherServlet 也是 Servlet。
6. Spring Boot 默认使用内嵌 Tomcat。
7. 传统 Java Web 项目通常打成 war 包部署到外部 Tomcat。
8. Spring Boot 项目通常打成 jar 包直接运行。
9. Tomcat 默认 HTTP 端口是 8080。
10. server.xml 是 Tomcat 核心配置文件。
11. webapps 是 Tomcat 默认项目部署目录。
12. logs 是排查 Tomcat 问题的重要目录。
13. 404 多半是路径或部署问题。
14. 500 多半是后端代码或配置异常。
15. Tomcat 9 和 Tomcat 10 要注意 javax 与 jakarta 的区别。

三十、总结

Tomcat 是 Java Web 开发中非常重要的基础组件。

如果把一个 Java Web 项目比作一家餐厅:

浏览器 = 顾客
HTTP 请求 = 顾客点单
Tomcat = 前台和服务员
Servlet / Controller = 厨师
Service = 后厨处理流程
DAO / Mapper = 采购和仓库管理员
数据库 = 仓库
HTTP 响应 = 做好的菜

顾客不会直接冲进后厨找厨师,而是先找前台点单。

同样,浏览器不会直接调用 Java 方法,而是先把请求发给 Tomcat。

Tomcat 接收请求,找到对应的 Java Web 应用,再把结果返回给浏览器。

最后用一句话总结 Tomcat:

Tomcat 是 Java Web 程序的运行容器,它负责监听端口、接收 HTTP 请求、管理 Servlet 生命周期、调用 Java Web 应用,并把响应结果返回给客户端。对于传统 Java Web 项目,它通常作为外部服务器运行 war 包;对于 Spring Boot 项目,它通常以内嵌 Tomcat 的形式跟随 jar 包一起启动。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐