Jersey 1 @Inject迁移至Jersey 2后依赖注入失效问题求助
核心原因:Jersey 1 与 Jersey 2 注入体系的区别
Jersey 1 自带专属注入容器,对com.sun.jersey.spi.inject.Inject和com.sun.jersey.spi.resource.Singleton的处理逻辑为:只要类在jersey.config.server.provider.packages指定的扫描路径下,就会自动识别带@Singleton注解的类,自动完成实例化、生命周期管理,无需额外配置即可直接通过@Inject注入。
Jersey 2 底层将注入容器替换为HK2,默认逻辑变更为:仅自动注册JAX-RS规范定义的组件(如带@Path的资源类、带@Provider的扩展类),普通业务类即使添加了javax.inject.Singleton注解,也不会被HK2自动扫描识别并加入容器,因此会抛出UnsatisfiedDependencyException依赖找不到的错误。
结合你项目的现状,绝大多数类没有被Spring管理,因此HK2和Spring两个容器中都没有对应的Bean实例,注入自然失败。
最低改造成本解决方案
推荐通过自定义HK2 Binder的方式注册需要注入的类,不需要修改原有业务逻辑,仅需新增1个配置类、修改少量web.xml配置即可:
- 新增自定义Binder类,绑定所有需要注入的业务类:
import org.glassfish.hk2.utilities.binding.AbstractBinder; import javax.inject.Singleton; public class CustomBeanBinder extends AbstractBinder { @Override protected void configure() { // 格式:bind(实现类).to(注入类型).in(作用域),如果注入类型就是实现类本身可以直接这么写 bind(APIConnectorHandler.class).to(APIConnectorHandler.class).in(Singleton.class); bind(RSearchClient.class).to(RSearchClient.class).in(Singleton.class); bind(BarcodeSearchClient.class).to(BarcodeSearchClient.class).in(Singleton.class); // 其他所有需要被@Inject注入的类,都按上述格式在此处添加绑定即可 } }
- 在web.xml的JerseyServlet配置中,注册上述自定义Binder:
<servlet> <servlet-name>JerseyServlet</servlet-name> <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class> <init-param> <param-name>jersey.config.server.provider.packages</param-name> <param-value> com.search, com.fasterxml.jackson.jaxrs.json </param-value> </init-param> <!-- 新增以下配置,注册自定义Binder --> <init-param> <param-name>jersey.config.server.provider.classnames</param-name> <param-value>com.search.config.CustomBeanBinder</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet>
配置完成后重启服务,HK2就能识别到你绑定的所有类,注入逻辑即可恢复正常。
可选迁移方案(适合后续逐步对接Spring)
如果后续计划将业务类逐步迁移到Spring管理,可以引入对应Spring版本的jersey-spring桥接依赖,开启Jersey和Spring的容器互通,之后只要把需要注入的类加上Spring的@Component注解并加入Spring扫描路径,Jersey就能直接从Spring容器中获取Bean完成注入,无需额外配置HK2 Binder。
内容的提问来源于stack exchange,提问作者Belphegor21

