0%

使用外置tomcat进行运行

Spring Boot 使用外置 Tomcat 部署详解:从配置到运行全流程

Spring Boot 默认集成了嵌入式 Tomcat,可通过 java -jar 直接启动应用,但在某些场景下(如企业统一管理服务器、需要特定 Tomcat 配置),需将应用部署到外置 Tomcat 中。从 “打包方式修改→依赖调整→启动类改造→部署运行” 四个维度,详细讲解 Spring Boot 应用部署到外置 Tomcat 的完整流程,并解答常见问题,帮你顺利完成外置容器部署。

外置 Tomcat 部署的适用场景

在决定使用外置 Tomcat 前,需明确其适用场景,避免不必要的复杂配置:

  • 企业级服务器管理:大型企业通常有统一的服务器集群(如 Tomcat 集群),需将应用部署到指定外置容器;
  • 自定义 Tomcat 配置:需要修改 Tomcat 核心配置(如线程池、连接器、安全配置),且这些配置无法通过 Spring Boot 嵌入式容器参数覆盖;
  • 多应用共享容器:多个 Spring Boot 应用共享同一个 Tomcat 实例,节省服务器资源;
  • 兼容性需求:依赖特定版本的 Tomcat(如因安全漏洞需使用定制化 Tomcat 版本)。

若无需上述场景,优先使用 Spring Boot 嵌入式 Tomcat(开发效率高、部署简单)。

部署到外置 Tomcat 的核心步骤

步骤 1:修改打包方式为 WAR

Spring Boot 默认打包为 JAR(包含嵌入式容器),部署到外置 Tomcat 需改为 WAR 包(不包含嵌入式容器,仅包含应用代码)。

pom.xml 中修改打包类型:

1
2
<!-- 关键:将打包方式从 jar 改为 war -->
<packaging>war</packaging>

步骤 2:排除嵌入式 Tomcat 依赖

为避免与外置 Tomcat 产生冲突,需排除 Spring Boot 自带的嵌入式 Tomcat 依赖,并添加 Servlet API 依赖(外置 Tomcat 会提供该 API)。

完整依赖配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!-- Web 依赖:排除嵌入式 Tomcat -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<!-- 移除嵌入式 Tomcat 依赖 -->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>

<!-- 关键:添加 Servlet API 依赖(外置 Tomcat 提供,编译时需要) -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version> <!-- 版本需与外置 Tomcat 兼容(Tomcat 8.5+ 对应 3.1) -->
<scope>provided</scope> <!-- 打包时不包含,由外置 Tomcat 提供 -->
</dependency>
版本兼容性说明:
外置 Tomcat 版本 兼容的 Servlet API 版本 建议 Spring Boot 版本
Tomcat 7.x Servlet 3.0 Spring Boot 1.x
Tomcat 8.5.x Servlet 3.1 Spring Boot 2.x
Tomcat 9.x Servlet 4.0 Spring Boot 2.x/3.x
Tomcat 10.x Jakarta Servlet 5.0 Spring Boot 3.x

注意:Spring Boot 3.x 开始使用 Jakarta EE 规范(包名从 javax.servlet 改为 jakarta.servlet),若使用 Tomcat 10+ 搭配 Spring Boot 3.x,需将 Servlet API 依赖改为 jakarta.servlet:jakarta.servlet-api:5.0.0

步骤 3:改造启动类(继承 SpringBootServletInitializer)

嵌入式 Tomcat 通过 main 方法启动应用,而外置 Tomcat 需通过 Servlet 容器初始化机制 启动,因此需改造启动类,继承 SpringBootServletInitializer 并重写 configure 方法(替代传统 web.xml 的作用)。

启动类改造示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

// 关键:继承 SpringBootServletInitializer,实现外置容器初始化
@SpringBootApplication
public class MyApplication extends SpringBootServletInitializer {

// 保留 main 方法(便于本地开发时用嵌入式 Tomcat 启动)
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}

// 关键:重写 configure 方法,指定 Spring Boot 应用的入口类
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
// 指向当前启动类(即本类),外置 Tomcat 会通过该方法加载 Spring 上下文
return builder.sources(MyApplication.class);
}
}
原理说明:
  • SpringBootServletInitializer 是 Spring Boot 提供的适配类,用于将 Spring 应用上下文集成到 Servlet 容器(如 Tomcat);
  • 外置 Tomcat 启动时,会调用 configure 方法,通过 SpringApplicationBuilder 构建并初始化 Spring 上下文,替代传统 web.xml 中配置的 ContextLoaderListener
  • 保留 main 方法不影响外置部署,且便于本地开发时使用嵌入式 Tomcat 快速启动(无需切换配置)。

步骤 4:打包并部署到外置 Tomcat

1. 打包 WAR 包

通过 Maven 命令打包(确保项目无编译错误):

1
2
# 清理并打包(跳过测试以加快速度)
mvn clean package -DskipTests

打包成功后,在项目的 target 目录下会生成 WAR 包(如 my-application-0.0.1-SNAPSHOT.war)。

2. 部署到外置 Tomcat
  • 将生成的 WAR 包复制到外置 Tomcat 的 webapps 目录下;
  • 启动 Tomcat(执行 bin/startup.shbin\startup.bat);
  • Tomcat 会自动解压 WAR 包,生成与 WAR 包同名的目录(如 my-application-0.0.1-SNAPSHOT)。
3. 访问应用

应用访问路径为:http://localhost:8080/[WAR包名]/[接口路径],例如:

  • WAR 包名为 my-application-0.0.1-SNAPSHOT.war
  • 接口路径为 /hello
  • 完整访问地址:http://localhost:8080/my-application-0.0.1-SNAPSHOT/hello
4. 自定义访问路径(可选)

若需简化访问路径(如去掉版本号),有两种方式:

  • 重命名 WAR 包:将 WAR 包重命名为 ROOT.war,访问路径变为 http://localhost:8080/[接口路径](Tomcat 默认根路径);
  • 配置 Context 路径:在 Tomcat 的 conf/server.xml 中添加 <Context> 配置(参考前文 “Tomcat 热部署” 部分),指定访问路径。

常见问题与解决方案

1. 部署后启动报错:ClassNotFoundException: javax.servlet.ServletContext

问题原因:
  • 未添加 javax.servlet-api 依赖,或依赖 scope 未设为 provided,导致编译时缺少 Servlet API;
  • Servlet API 版本与外置 Tomcat 不兼容(如 Tomcat 8.5 使用 Servlet 3.0 依赖)。
解决方案:
  • 确保添加正确的 Servlet API 依赖(版本与 Tomcat 匹配),且 scopeprovided
  • 检查 pom.xml 中是否有冲突的 Servlet API 依赖(如其他第三方依赖引入了低版本 Servlet API)。

2. 应用启动成功,但访问接口报 404

问题原因:
  • 访问路径错误:未包含 WAR 包名(如 WAR 包为 demo.war,需访问 http://localhost:8080/demo/hello);
  • 上下文路径配置冲突:Spring Boot 配置了 server.servlet.context-path,与 WAR 包名叠加导致路径错误;
  • 启动类未继承 SpringBootServletInitializer:外置 Tomcat 无法加载 Spring 上下文,导致接口未注册。
解决方案:
  • 确认访问路径包含 WAR 包名(或已配置为根路径);
  • 移除 application.properties 中的 server.servlet.context-path 配置(外置 Tomcat 以 WAR 包名作为上下文路径);
  • 检查启动类是否正确继承 SpringBootServletInitializer 并实现 configure 方法。

3. 依赖冲突:org.springframework.web.context.ContextLoaderListener 重复

问题原因:
  • 项目中手动添加了 spring-web 等依赖,与 Spring Boot Starter 依赖冲突,导致 Tomcat 启动时加载多个 ContextLoaderListener
解决方案:
  • 优先使用 Spring Boot Starter 依赖(如 spring-boot-starter-web),避免手动添加零散的 Spring 依赖;

  • 通过mvn dependency:tree命令查看依赖树,排除冲突的依赖:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <dependency>
    <groupId>xxx</groupId>
    <artifactId>xxx</artifactId>
    <exclusions>
    <exclusion>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    </exclusion>
    </exclusions>
    </dependency>

4. 外置 Tomcat 启动慢,日志提示 “DataSource 初始化超时”

问题原因:
  • 外置 Tomcat 启动时,Spring 初始化数据源(如数据库连接池)耗时过长,超过 Tomcat 的默认超时时间。
解决方案:
  • 优化数据源配置(如减少初始化连接数、调整连接超时参数);
  • 延长 Tomcat 的启动超时时间:修改 conf/server.xml<Connector> 标签,添加 connectionTimeout="60000"(60 秒);
  • 配置 Spring 延迟初始化数据源:在数据源 Bean 上添加 @Lazy 注解,延迟到首次使用时初始化。

部署与开发的最佳实践

1. 区分开发与生产环境

  • 开发环境:使用嵌入式 Tomcat(通过 main 方法启动),配合热部署工具(如 spring-boot-devtools),提高开发效率;
  • 生产环境:部署到外置 Tomcat,通过 application-prod.properties 配置生产环境参数(如数据库地址、日志级别),避免硬编码。
多环境配置示例:
1
2
3
4
5
6
7
# application-dev.properties(开发环境,嵌入式 Tomcat)
server.port=8080
spring.datasource.url=jdbc:mysql://localhost:3306/dev_db

# application-prod.properties(生产环境,外置 Tomcat)
spring.datasource.url=jdbc:mysql://prod-db:3306/prod_db
logging.level.root=WARN

启动时通过 --spring.profiles.active=prod 指定环境(外置 Tomcat 可通过 set SPRING_PROFILES_ACTIVE=prod 设置环境变量)。

2. 外置 Tomcat 性能优化

部署到生产环境时,需优化外置 Tomcat 配置以提升性能:

  • 调整线程池:修改conf/server.xml<Executor>标签,配置核心线程数、最大线程数:

    1
    2
    <Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
    maxThreads="200" minSpareThreads="20" maxIdleTime="60000"/>
  • 启用压缩:开启 HTTP 压缩,减少网络传输量:

    1
    2
    3
    <Connector executor="tomcatThreadPool" port="8080" protocol="HTTP/1.1"
    compression="on" compressionMinSize="2048"
    compressableMimeType="text/html,text/xml,text/css,application/json"/>
  • 禁用 AJP 连接器:若不使用 AJP 协议(如与 Apache 服务器集成),注释掉 conf/server.xml 中的 AJP 连接器,减少资源占用。

总结

Spring Boot 应用部署到外置 Tomcat 的核心是 “适配 Servlet 容器的初始化机制”,关键步骤可概括为:

  1. 修改打包方式为 WAR;
  2. 排除嵌入式 Tomcat 依赖,添加 Servlet API 依赖;
  3. 启动类继承 SpringBootServletInitializer,重写 configure 方法;
  4. 打包 WAR 包并部署到外置 Tomcat 的 webapps 目录

欢迎关注我的其它发布渠道

表情 | 预览
快来做第一个评论的人吧~
Powered By Valine
v1.3.10