Tomcat9升级至10时Jersey RequestContext单例范围异常求助
Tomcat 10升级后Jersey HK2 RequestContext单例范围异常解决
问题背景
将Web应用从Tomcat 9.0.78升级至10.0.14,已完成javax.servlet到jakarta.servlet命名空间迁移,同时升级了Hibernate。目前卡在启动阶段,Tomcat日志中出现异常:
java.lang.IllegalArgumentException: The implementation class org.glassfish.jersey.inject.hk2.RequestContext must be in the Singleton scope
已尝试操作
- 移除Tomcat/lib下的
jakarta.inject-2.6.1.jar和jakarta.inject-api-2.0.0.jar,但触发类未找到异常 - 排查源码发现
org.glassfish.jersey.inject.hk2.RequestContext未标注Jakarta单例注解
环境信息
依赖版本
- 所有Jersey jar包版本为3.0.2,包含问题类的是
jersey-hk2-3.0.2.jar - HK2依赖配置:
<h2k.version>3.0.2</h2k.version> <h2k.locator.version>3.0.1</h2k.locator.version> <jakarta.inject.version>2.6.1</jakarta.inject.version> <dependency> <groupId>org.glassfish.hk2</groupId> <artifactId>hk2-api</artifactId> <version>${h2k.version}</version> </dependency> <dependency> <groupId>org.glassfish.hk2</groupId> <artifactId>hk2-locator</artifactId> <version>${h2k.locator.version}</version> </dependency> <dependency> <groupId>org.glassfish.hk2</groupId> <artifactId>hk2-utils</artifactId> <version>${h2k.version}</version> </dependency>
完整异常栈
023 12:14:49.238 SEVERE [main] org.apache.catalina.core.StandardContext.loadOnStartup Servlet [jersey-serlvet] in web application [/ngen] threw load() exception java.lang.IllegalArgumentException: The implementation class org.glassfish.jersey.inject.hk2.RequestContext must be in the Singleton scope at org.jvnet.hk2.internal.ServiceLocatorImpl.checkConfiguration(ServiceLocatorImpl.java:1700) at org.jvnet.hk2.internal.ServiceLocatorImpl.addConfiguration(ServiceLocatorImpl.java:2095) at org.jvnet.hk2.internal.DynamicConfigurationImpl.commit(DynamicConfigurationImpl.java:262) at org.glassfish.hk2.utilities.ServiceLocatorUtilities.bind(ServiceLocatorUtilities.java:166) at org.glassfish.jersey.inject.hk2.AbstractHk2InjectionManager.<init>(AbstractHk2InjectionManager.java:65) at org.glassfish.jersey.inject.hk2.ImmediateHk2InjectionManager.<init>(ImmediateHk2InjectionManager.java:38) at org.glassfish.jersey.inject.hk2.Hk2InjectionManagerFactory$Hk2InjectionManagerStrategy$1.createInjectionManager(Hk2InjectionManagerFactory.java:55) at org.glassfish.jersey.inject.hk2.Hk2InjectionManagerFactory.create(Hk2InjectionManagerFactory.java:73) at org.glassfish.jersey.internal.inject.Injections.createInjectionManager(Injections.java:69) at org.glassfish.jersey.server.ApplicationHandler.<init>(ApplicationHandler.java:259) at org.glassfish.jersey.servlet.WebComponent.<init>(WebComponent.java:311) at org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:154) at org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:347) at jakarta.servlet.GenericServlet.init(GenericServlet.java:158) at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1165) at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1118) at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1011) at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4906) at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5213) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:726) at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:698) at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:747) at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:1188) at org.apache.catalina.startup.HostConfig$DeployDirectory.run(HostConfig.java:2023) at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539) 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:123) at org.apache.catalina.startup.HostConfig.deployDirectories(HostConfig.java:1098) at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:480) at org.apache.catalina.startup.HostConfig.start(HostConfig.java:1708) at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:320) at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:123) at org.apache.catalina.util.LifecycleBase.setStateInternal(LifecycleBase.java:423) at org.apache.catalina.util.LifecycleBase.setState(LifecycleBase.java:366) at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:946) at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:886) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1396) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1386) 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:919) at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:263) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) at org.apache.catalina.core.StandardService.startInternal(StandardService.java:432) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:927) 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:345) at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:476)
解决方案尝试
1. 统一HK2版本
当前hk2-locator版本为3.0.1,其他HK2依赖为3.0.2,版本不一致会引发兼容性问题。修改配置统一版本:
<h2k.locator.version>3.0.2</h2k.locator.version>
重新打包部署后验证异常是否消失。
2. 排除冲突的Jakarta Inject依赖
Tomcat/lib下的jakarta.inject jar与项目依赖版本可能冲突。在项目HK2依赖中排除jakarta.inject-api,确保依赖版本统一:
<dependency> <groupId>org.glassfish.hk2</groupId> <artifactId>hk2-api</artifactId> <version>${h2k.version}</version> <exclusions> <exclusion> <groupId>jakarta.inject</groupId> <artifactId>jakarta.inject-api</artifactId> </exclusion> </exclusions> </dependency>
同时清理Tomcat/lib下的冗余jakarta.inject jar,只保留与项目依赖匹配的2.6.1版本。
3. 升级Jersey版本
Jersey 3.0.2可能存在该已知问题,尝试升级到3.0.3或更高版本,后续版本大概率已修复该兼容性问题。
4. 手动绑定RequestContext为单例
若上述方法无效,自定义HK2绑定器强制注册RequestContext为单例:
import org.glassfish.hk2.utilities.binding.AbstractBinder; import org.glassfish.jersey.inject.hk2.RequestContext; import jakarta.inject.Singleton; public class CustomBinder extends AbstractBinder { @Override protected void configure() { bind(RequestContext.class).to(RequestContext.class).in(Singleton.class); } }
在Jersey应用类中注册该绑定器:
public class JerseyApplication extends ResourceConfig { public JerseyApplication() { register(new CustomBinder()); // 其他资源/过滤器注册 } }
内容的提问来源于stack exchange,提问作者RichardFeynman
相关产品推荐
相关产品推荐

