Spring 6.0.11部署Tomcat10遇ClassCastException问题求助
将 Spring 4.2.4 迁移至 Spring 6.0.11 后,部署到 Tomcat 10 时抛出如下类型转换异常:
java.lang.ClassCastException: class org.springframework.web.servlet.DispatcherServlet cannot be cast to class jakarta.servlet.Servlet (org.springframework.web.servlet.DispatcherServlet is in unnamed module of loader org.apache.catalina.loader.ParallelWebappClassLoader @53bd8fca; jakarta.servlet.Servlet is in unnamed module of loader java.net.URLClassLoader @7eda2dbb)
完整异常栈信息:
SEVERE: Servlet [spring] in web application [/SpringMVCPagination] threw load() exception java.lang.ClassCastException: class org.springframework.web.servlet.DispatcherServlet cannot be cast to class jakarta.servlet.Servlet (org.springframework.web.servlet.DispatcherServlet is in unnamed module of loader org.apache.catalina.loader.ParallelWebappClassLoader @53bd8fca; jakarta.servlet.Servlet is in unnamed module of loader java.net.URLClassLoader @7eda2dbb) at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:865) at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:805) at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4637) at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:4930) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1328) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1318) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75) at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:145) at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:866) at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:846) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1328) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1318) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75) at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:145) at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:866) at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:241) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) at org.apache.catalina.core.StandardService.startInternal(StandardService.java:428) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:918) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) at org.apache.catalina.startup.Catalina.start(Catalina.java:795) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:568) at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:347) at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:478)
问题原因
Tomcat 10 及以上版本使用 Jakarta EE API(包前缀为jakarta.servlet.*),而 Spring 4.x 依赖的是旧版 Java EE API(包前缀为javax.servlet.*)。即便 Spring 6 原生支持 Jakarta EE,迁移时若存在以下遗漏仍会触发异常:
- 项目残留旧的
javax.servlet相关依赖 - web.xml配置仍使用Java EE命名空间
- 类路径中同时存在
javax.servlet和jakarta.servlet类,引发类加载冲突
解决步骤
1. 替换Servlet API依赖
将项目中所有javax.servlet相关依赖替换为Jakarta EE版本:
- Maven项目:移除
javax.servlet:javax.servlet-api依赖,添加:
<dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> <version>6.0.0</version> <scope>provided</scope> </dependency>
- 检查其他依赖(如Spring MVC、JSP API等),确保它们适配Jakarta EE(Spring 6本身已支持,重点排查第三方库)。
2. 更新web.xml配置
将web.xml的命名空间切换为Jakarta EE规范:
旧配置开头:
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0">
替换为:
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd" version="6.0">
同时确认Servlet、Filter等配置的类路径正确,未引用javax.servlet下的类。
3. 排查类路径冲突
- 清理项目target目录,重新构建
- 执行
mvn dependency:tree查看依赖树,若有依赖传递引入javax.servlet包,直接排除:
<dependency> <groupId>依赖组ID</groupId> <artifactId>依赖包ID</artifactId> <exclusions> <exclusion> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> </exclusion> </exclusions> </dependency>
4. 确认环境兼容性
Spring 6.0.x要求:
- JDK版本17及以上
- Jakarta EE 9.0+(Tomcat 10满足该要求)
检查项目编译级别是否设置为JDK 17及以上。
内容的提问来源于stack exchange,提问作者Ramesh Reddy

