升级至Tomcat10后QuartzInitializerServlet无法匹配Servlet类型报错求助
Tomcat 10及以上版本实现的是Jakarta EE规范,将原javax.servlet包下的所有Servlet API全量迁移到了jakarta.servlet包下。当前使用的Quartz版本内置的QuartzInitializerServlet仍基于旧的javax.servlet.Servlet接口实现,Apache官方迁移工具仅会替换项目自身源码、配置文件中的包名引用,不会修改第三方依赖Jar包内部的实现逻辑,因此会抛出Servlet类不匹配的错误。
- 核对当前项目引入的Quartz版本:2.3.2及更早版本的Quartz均基于Java EE(javax包)构建,无原生Jakarta EE适配
- 核对容器Servlet API版本:Tomcat 10自带的Servlet API为Jakarta EE 5.0+版本,类路径下不存在
javax.servlet.Servlet接口定义 - 核对迁移工具执行范围:确认迁移工具未处理第三方依赖的字节码,旧版Quartz依赖中的Servlet类未完成包名转换
方案1:升级Quartz到Jakarta适配版本(推荐)
Quartz从2.4.0版本开始官方提供Jakarta EE适配包,类名、配置逻辑和旧版本完全兼容,无需修改web.xml中的配置项,仅需要替换依赖即可。
以Maven依赖为例,将原有Quartz依赖替换为带jakarta分类器的版本:
<dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>2.4.0</version> <classifier>jakarta</classifier> </dependency>
替换完成后重启容器即可正常加载Quartz初始化Servlet。
方案2:自定义Quartz初始化Servlet
如果受项目其他依赖限制无法升级Quartz版本,可以废弃Quartz自带的初始化Servlet,自行实现基于Jakarta Servlet API的初始化逻辑:
- 新建自定义Servlet类,手动完成Quartz调度器的初始化、启动、销毁逻辑,兼容原有web.xml中配置的初始化参数:
import jakarta.servlet.ServletConfig; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServlet; import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.quartz.impl.StdSchedulerFactory; public class CustomQuartzInitializer extends HttpServlet { private Scheduler scheduler; @Override public void init(ServletConfig config) throws ServletException { super.init(config); String startOnLoad = config.getInitParameter("start-scheduler-on-load"); try { scheduler = StdSchedulerFactory.getDefaultScheduler(); if ("true".equalsIgnoreCase(startOnLoad)) { scheduler.start(); } config.getServletContext().setAttribute(Scheduler.class.getName(), scheduler); } catch (SchedulerException e) { throw new ServletException("Quartz调度器初始化失败", e); } } @Override public void destroy() { String shutdownOnUnload = getInitParameter("shutdown-on-unload"); if ("true".equalsIgnoreCase(shutdownOnUnload) && scheduler != null) { try { scheduler.shutdown(); } catch (SchedulerException e) { e.printStackTrace(); } } } }
- 修改web.xml中Quartz初始化Servlet的
servlet-class配置为上述自定义类的全限定名,其余init-param、load-on-startup配置保持不变即可。
方案3:降级Tomcat版本
如果暂时没有改造计划,可以将Tomcat降级到9.x版本,Tomcat 9是最后一个基于Java EE(javax包)规范的Tomcat稳定版本,和旧版Quartz原生兼容,不需要修改任何代码或依赖。
注意:不要尝试在Tomcat 10中手动引入javax.servlet-api依赖,会和容器自带的Jakarta Servlet API产生类加载冲突,引发更多不可预期的运行错误。
内容的提问来源于stack exchange,提问作者Vlad Dieaconu

