Spring Boot部署外部Tomcat 8.5时OJDBC抛出NoClassDefFoundError
我之前也碰到过一模一样的情况——内嵌Tomcat跑起来毫无问题,一部署到外部Tomcat就报这个错,核心原因其实是Oracle驱动的国际化依赖没被正确打包到war包中,下面给你一步步解决的方法:
问题根源
oracle/i18n/util/LocaleMapper这个类属于Oracle的orai18n模块,它是ojdbc驱动处理国际化、本地化相关逻辑的必要依赖。Spring Boot内嵌Tomcat会自动把所有runtime依赖都加载到类路径里,但部署到外部Tomcat时,war包如果没包含这个依赖,Tomcat就找不到对应的类,直接抛出NoClassDefFoundError。
解决方案
1. 补充orai18n依赖到build.gradle
打开你的build.gradle文件,确保除了ojdbc驱动外,还引入了对应版本的orai18n依赖。注意版本要和ojdbc保持一致,比如用ojdbc8的话,就用同版本的orai18n:
dependencies { // 其他默认依赖(比如spring-boot-starter-web等)... implementation 'com.oracle.database.jdbc:ojdbc8:19.3.0.0' implementation 'com.oracle.database.nls:orai18n:19.3.0.0' }
2. 避免将Oracle依赖标记为provided
检查你的build.gradle里有没有把ojdbc相关依赖设为providedRuntime或者provided,比如这种配置:
// 这种配置要删掉! providedRuntime 'com.oracle.database.jdbc:ojdbc8:19.3.0.0'
provided意味着依赖由容器(这里是Tomcat)提供,但Tomcat本身根本不带Oracle驱动,所以打包时会把这些依赖排除在war包外,自然会找不到类。必须用implementation或者runtime来声明这些依赖,确保它们被打包到war的WEB-INF/lib目录下。
3. 验证war包内容
执行打包命令:
./gradlew clean build
找到build/libs目录下生成的war包,解压后查看WEB-INF/lib文件夹,确认里面有ojdbc8.jar和orai18n.jar两个文件。如果没有,回到build.gradle检查依赖配置是否正确。
4. 重新部署到Tomcat
把验证过的war包放到Tomcat的webapps目录下,启动Tomcat,此时应该不会再出现LocaleMapper的找不到类错误了。
为什么内嵌Tomcat没问题?
Spring Boot的内嵌Tomcat是通过fat jar方式运行的,打包时会把所有runtime依赖(包括orai18n)都打包到jar里,启动时会自动加载这些依赖到类路径,所以不会出现类找不到的情况。而外部Tomcat是依赖war包自带的lib目录,所以必须确保所有必要依赖都在里面。
内容的提问来源于stack exchange,提问作者Snæbjørn

