Spring Boot 3应用内嵌Tomcat运行正常,但部署到外部Tomcat 10.1.7时出现404错误
看起来你遇到的是Spring Boot部署到外部Tomcat时的典型配置遗漏问题,连最小化Demo都出现同样错误,说明核心启动逻辑有缺失。我帮你梳理下最关键的原因和解决步骤:
核心问题:外部Tomcat无法初始化Spring Boot上下文
当把Spring Boot打包成war包部署到外部Tomcat时,不能只依赖IDE里的SpringApplication.run()启动方式——外部Tomcat需要通过SpringBootServletInitializer来触发Spring上下文的初始化,否则你的应用根本没被Tomcat加载,自然会返回404。
步骤1:修改启动类,继承SpringBootServletInitializer
找到你的应用启动类(比如ProjetoApplication或Demo里的启动类),让它继承SpringBootServletInitializer并重写configure方法:
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; @SpringBootApplication public class ProjetoApplication extends SpringBootServletInitializer { // 保留该方法,不影响内嵌Tomcat运行 public static void main(String[] args) { SpringApplication.run(ProjetoApplication.class, args); } @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { // 告诉外部Tomcat哪个是Spring Boot的启动入口 return application.sources(ProjetoApplication.class); } }
步骤2:完善pom.xml依赖配置
你的最小化Demo还需要添加spring-boot-starter-tomcat的provided依赖,避免war包内嵌Tomcat的jar和外部Tomcat冲突:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <scope>provided</scope> </dependency>
步骤3:移除application.properties中的上下文路径配置
你设置了server.servlet.context-path=/projeto,但部署到外部Tomcat时,上下文路径由webapps下的war包/文件夹名称决定。如果war包名叫projeto,实际访问路径会变成/projeto/projeto,直接导致访问/projeto时找不到资源。
建议删除server.servlet.context-path这行配置,直接通过war包名称控制上下文路径,和IDE里的访问逻辑保持一致。
步骤4:验证应用是否被Tomcat加载
之前你的logback没有输出日志,大概率是应用根本没启动。可以查看Tomcat的logs/localhost.log,里面应该会有Spring Boot启动的日志信息。如果看到类似Started ProjetoApplication in X seconds的内容,说明应用已成功加载,此时访问localhost:8080/projeto就能正常访问了。
额外检查点
- 确认webapps下的
projeto文件夹是完整解压的war包内容,不要直接放war包(Tomcat会自动解压,但手动操作要确保解压完整)。 - 解压war包检查
WEB-INF/classes下是否有控制器和启动类的class文件,WEB-INF/lib下是否包含所有必要的Spring依赖。 - Tomcat 10.1.7确实支持Spring Boot 3.x和Java 19,版本兼容性没问题,不用更换Tomcat版本。
按照这些步骤修改后,不管是完整应用还是最小化Demo,都应该能正常部署到外部Tomcat了。
备注:内容来源于stack exchange,提问作者Joao Branco

