Grails 5.1.7应用部署Tomcat 9.0.44访问返回HTTP 404问题求助
核心问题根因
你遇到的404问题是兼容配置缺失叠加版本不匹配导致的,本地grails run-app走内嵌容器不需要外部部署相关配置,所以运行正常;部署时Tomcat没有正确加载Grails应用上下文,也不会抛出明显错误日志,所有请求直接返回404。
第一步:先修正Tomcat版本匹配问题
- Grails 5.1.7 基于Spring Boot 2.7.x构建,完全不支持Tomcat 10.x:Tomcat 10将Java EE包名从
javax.*全面迁移到jakarta.*,Spring Boot 2.x不兼容该包名变更,你测试环境2的Tomcat 10.0.10无论怎么配置都无法正常运行。 - 你配置的
ext['tomcat.version'] = '10.0.10'仅修改内嵌Tomcat版本,对外部独立部署的Tomcat版本适配没有任何作用,直接删除该配置。 - 两个测试环境统一使用Tomcat 9.0.x版本(推荐9.0.70+稳定版),JDK 11版本兼容无问题。
第二步:修正War包构建依赖配置
你之前直接删除spring-boot-starter-tomcat依赖的操作是错误的,该依赖提供Servlet API编译期支持,直接删除会导致War包结构缺失,正确配置是修改依赖范围而非删除:
打开build.gradle,调整依赖配置:
dependencies { // 保留你原有所有依赖,仅修改tomcat starter的scope providedCompile "org.springframework.boot:spring-boot-starter-tomcat" }
配置后打出来的War包会把内嵌Tomcat相关依赖放到WEB-INF/lib-provided目录,外部部署时Tomcat不会加载该目录下的容器类,避免类冲突,同时编译期不会缺失Servlet相关类。
第三步:补全外部部署必需的Servlet初始化类
这是90%的Grails 5升级用户踩的坑:Grails 5默认通过create-app生成的项目只有本地启动的main方法入口,没有外部Tomcat部署需要的Servlet初始化器,Tomcat部署时无法识别Spring Boot应用入口,不会加载应用上下文,直接导致所有请求404且无报错。
在你项目的grails-app/init/[你的项目基础包名]/路径下,找到原有Application.groovy启动类,添加如下初始化器代码(可以直接写在同一个文件里):
package com.your.project.package // 替换成你自己项目的实际包名 import grails.boot.GrailsApp import grails.boot.config.GrailsAutoConfiguration import org.springframework.boot.builder.SpringApplicationBuilder import org.springframework.boot.web.servlet.support.SpringBootServletInitializer class Application extends GrailsAutoConfiguration { static void main(String[] args) { GrailsApp.run(Application, args) } } /** * 外部Tomcat部署必需的初始化类,缺失则无法加载应用上下文 */ class ServletInitializer extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { application.sources(Application) } }
第四步:重新构建部署验证
- 执行
grails clean清空所有旧的构建缓存,避免旧的编译产物干扰 - 执行
grails war重新生成War包,生成的War包默认路径在build/libs目录下 - 部署注意事项:
- 若要部署到Tomcat根路径,将War包重命名为
ROOT.war后放到Tomcat的webapps目录 - 若保留原War包名(比如
myapp.war),访问时需要带上上下文路径,即http://你的域名:端口/myapp,不要直接访问根路径导致误判404
- 启动Tomcat后查看
logs/catalina.out日志,能看到Grails应用启动的Banner和初始化日志即代表加载成功。
补充验证点
解压你生成的War包,检查WEB-INF目录下是否存在lib-provided文件夹,且文件夹内包含spring-boot-starter-tomcat相关jar包,若不存在则代表依赖scope配置错误,需要重新检查build.gradle配置。
你之前Grails 4.0.5版本可以直接部署是因为旧版本的Grails构建插件默认自动生成了Servlet初始化逻辑,Grails 5将该逻辑移除,需要开发者手动添加。
内容的提问来源于stack exchange,提问作者vrivon

