Spring Boot应用部署至外部Tomcat后页面返回404错误
内嵌Tomcat跑起来一切正常,扔到外部Tomcat就404,这种情况我碰到过好多次了,大概率是WAR部署的几个关键配置没做对。结合你用的Tomcat 8.0.48,咱们一步步排查:
1. 先看启动类是不是没继承SpringBootServletInitializer
这是外部Tomcat能识别Spring Boot应用的核心!你的Application.java必须继承SpringBootServletInitializer并重写configure方法,不然外部Tomcat根本不知道怎么初始化Spring上下文,直接就404了。
正确的写法应该是这样:
@SpringBootApplication public class Application extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { return application.sources(Application.class); } public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
如果你的启动类没这么写,先改了再说。
2. 检查pom.xml的打包配置有没有踩坑
第一步:确认打包类型是war
必须在pom.xml里明确写:
<packaging>war</packaging>
要是写成jar,那打出来的包根本不是Tomcat能识别的WAR包,肯定报错。
第二步:排除内嵌Tomcat依赖(可选但强烈推荐)
避免内嵌Tomcat和外部Tomcat的依赖冲突,把spring-boot-starter-tomcat的scope设为provided:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <scope>provided</scope> </dependency>
另外,spring-boot-maven-plugin必须配上,保证打包出符合规范的WAR:
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
3. 别搞混上下文路径!
内嵌Tomcat默认是根路径/,但外部Tomcat会把WAR包的名字当成上下文路径。比如你的WAR包叫my-spring-app.war,那访问路径得是http://localhost:8080/my-spring-app/,而不是直接http://localhost:8080/,这是很多人踩的第一个坑。
想直接用根路径访问的话,要么把WAR包重命名成ROOT.war,要么去Tomcat的conf/server.xml里加个Context配置:
<Context path="" docBase="my-spring-app" reloadable="true"/>
4. application.properties里别瞎配置
别在配置文件里硬写端口或者上下文路径,会干扰外部Tomcat的配置:
# 把这个注释掉!外部Tomcat用自己的端口,不用你指定 # server.port=8080 # 除非你明确要固定上下文路径,否则别写这个,让Tomcat自动识别WAR包名 # server.servlet.context-path=/my-app
5. 看日志找线索!
如果上面的配置都没问题,赶紧去Tomcat的logs目录看catalina.out或者localhost.log,启动时的报错信息会直接告诉你问题在哪:
- 如果看到
ClassNotFoundException,那就是依赖没打包全,检查pom.xml里的依赖范围是不是设错了 - 如果是Spring上下文初始化失败的报错,比如
BeanCreationException,那就是代码里的bean配置有问题,跟着错误提示改就行
举个常见的错误日志例子:
SEVERE: Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userService' defined in file [xxx/UserService.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.example.UserService]: Constructor threw exception; nested exception is java.lang.NullPointerException
这种情况就去查UserService的构造方法是不是空指针了。
6. 版本兼容性得注意
Tomcat 8.0.48比较老,Spring Boot 2.2及以上版本对它的支持已经不太友好了。如果你的Spring Boot版本是2.2+,要么降级到2.1.x系列,要么把Tomcat升级到8.5以上版本,不然可能会有莫名其妙的启动失败问题。
内容的提问来源于stack exchange,提问作者MSV

