Java 11/Jersey/HK2依赖注入异常问题求助
Java 11/Jersey/HK2 依赖注入问题排查
在Java 11/Jersey/HK2环境下,资源类BackboneController注入IEnvironmentService等服务时出现依赖注入异常。其中IEnvironmentService的实现类EnvironmentService通过@Inject注入EnvironmentRepository失败,但将注入改为手动new EnvironmentRepository()可正常运行;结构类似的BackboneService与BackboneRepository注入却能正常工作。
相关代码
资源类 BackboneController
@Path("/backbone") public class BackboneController extends GenericController { @Inject private IEnvironmentService _environmentService; @Inject private IAuthenticationHelper _authenticationHelper; @Inject private IBackboneService _backboneService; @GET @Path("version") @Produces(MediaType.APPLICATION_JSON) public Response version( @HeaderParam("Authorization") String token) throws Exception { var credentials = _authenticationHelper.detokenizeCredentials(token); var backendVersionHandler = new BackendVersionResponseDto(_backboneService.getBackendVersion(credentials)); var apiVersionHandler = new Properties(); apiVersionHandler.load(BackboneController.class.getResourceAsStream("/project.properties")); return Response.status(Status.OK) .entity(new GenericResponse( new VersionResponseDto(backendVersionHandler.getBackend(), apiVersionHandler.getProperty("version")))) .build(); } @GET @Produces(MediaType.APPLICATION_JSON) @Path("url") public Response getUrl( @HeaderParam("Authorization") String token) throws Exception { var credentials = _authenticationHelper.detokenizeCredentials(token); var urlDto = new UrlResponseDto(_backboneService.getUrl(credentials)); return Response.status(Status.OK).entity(new GenericResponse(urlDto)).build(); } @GET @Produces(MediaType.APPLICATION_JSON) @Path("context-path-to-etc") public Response getContextPathToEtc( @HeaderParam("Authorization") String token) throws Exception { var credentials = _authenticationHelper.detokenizeCredentials(token); if (!_backboneService.areCredentialsValid(credentials)) throw new WebApplicationException(Response.status(Status.UNAUTHORIZED).build()); var contextPathToEtcDto = new ContextPathToEtcResponseDto(_environmentService.getEtcPathInContext()); return Response.status(Status.OK).entity(new GenericResponse(contextPathToEtcDto)).build(); } }
IEnvironmentService 接口与实现
@Contract public interface IEnvironmentService { public void environmentSet(Credentials credentials, String key, String value) throws Exception; public void environmentUnset(Credentials credentials, String key) throws Exception; public String environmentGet(Credentials credentials, String key) throws Exception; public String getEtcPathInContext(); } @Service public class EnvironmentService implements IEnvironmentService { @Inject private EnvironmentRepository _environmentRepository; @Override public void environmentSet(Credentials credentials, String key, String value) throws Exception { _environmentRepository.environmentSet(credentials, key, value); } @Override public void environmentUnset(Credentials credentials, String key) throws Exception { _environmentRepository.environmentUnset(credentials, key); } @Override public String environmentGet(Credentials credentials, String key) throws Exception { return _environmentRepository.environmentGet(credentials, key); } @Override public String getEtcPathInContext() { return _environmentRepository.getEtcPathInContext(); } }
IEnvironmentRepository 接口与实现
@Contract public interface IEnvironmentRepository { public void environmentSet(Credentials credentials, String key, String value) throws Exception; public void environmentUnset(Credentials credentials, String key) throws Exception; public String environmentGet(Credentials credentials, String key) throws Exception; public String getEtcPathInContext(); } @Service public class EnvironmentRepository extends GenericRepository implements IEnvironmentRepository { @Inject private IContextFinder _contextFinder; @Override public void environmentSet(Credentials credentials, String key, String value) throws Exception { _connector.execute(credentials.getUsername(), credentials.getPassword(), String.format("SELECT backbone.environment_set(%s, %s)'", new SqlParameter("p_key", key), new SqlParameter("p_value", value))); } @Override public void environmentUnset(Credentials credentials, String key) throws Exception { _connector.execute(credentials.getUsername(), credentials.getPassword(), String.format("SELECT backbone.environment_unset(%s)", new SqlParameter("p_key", key))); } @Override public String environmentGet(Credentials credentials, String key) throws Exception { return _connector.queryText(credentials.getUsername(), credentials.getPassword(), String.format("SELECT backbone.environment_get(%s)", new SqlParameter("p_key", key))); } @Override public String getEtcPathInContext() { return _contextFinder.getEtcPathInContext(); } }
抽象绑定器与资源配置类
public class BackboneBinder extends AbstractBinder { @Override protected void configure() { bind(BackboneRepository.class).to(IBackboneRepository.class); bind(BackboneService.class).to(IBackboneService.class); bind(EnvironmentRepository.class).to(IEnvironmentRepository.class).in(PerLookup.class); bind(EnvironmentService.class).to(IEnvironmentService.class); bind(ContextFinder.class).to(IContextFinder.class); bind(ParametersHandler.class).to(IParametersHandler.class); bind(AuthenticationHelper.class).to(IAuthenticationHelper.class); } } public class ApplicationConfiguration extends ResourceConfig { public ApplicationConfiguration() { // Dependencies binders register(new BackboneBinder()); packages("com.bfaconsultora"); } }
异常信息
javax.servlet.ServletException: A MultiException has 5 exceptions. They are: 1. org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=EnvironmentRepository,parent=EnvironmentService,qualifiers={},position=-1,optional=false,self=false,unqualified=null,804331421) 2. java.lang.IllegalArgumentException: While attempting to resolve the dependencies of com.bfaconsultora.rest.backbone.services.EnvironmentService errors were found 3. java.lang.IllegalStateException: Unable to perform operation: resolve on com.bfaconsultora.rest.backbone.services.EnvironmentService 4. java.lang.IllegalArgumentException: While attempting to resolve the dependencies of com.bfaconsultora.rest.backbone.controllers.BackboneController errors were found 5. java.lang.IllegalStateException: Unable to perform operation: resolve on com.bfaconsultora.rest.backbone.controllers.BackboneController org.glassfish.jersey.servlet.WebComponent.serviceImpl(WebComponent.java:408) org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:346) org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:365) org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:318) org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:205) org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
排查方向
- 检查注入类型匹配:EnvironmentService中直接注入了实现类
EnvironmentRepository,但绑定器仅配置了EnvironmentRepository.class到IEnvironmentRepository.class的映射,HK2不会自动将实现类本身注册到容器。对比BackboneService,其注入的是接口IBackboneRepository,与绑定规则匹配,所以能正常注入。 - 补充实现类绑定:在
BackboneBinder的configure()方法中添加bind(EnvironmentRepository.class).in(PerLookup.class);,显式将EnvironmentRepository实现类注册到HK2容器,让注入实现类的代码能找到实例。 - 统一注入接口:修改EnvironmentService的注入代码为
@Inject private IEnvironmentRepository _environmentRepository;,遵循依赖倒置原则,同时直接匹配现有绑定规则,这也是Backbone组件正常工作的核心原因。 - 检查父类依赖:EnvironmentRepository继承自
GenericRepository,确认GenericRepository中的_connector等依赖是否被正确注入,若父类存在未解决的依赖,会导致子类无法被实例化。 - 验证扫描与绑定优先级:
ApplicationConfiguration中调用packages("com.bfaconsultora")会让HK2自动扫描带@Service注解的类,但手动绑定的规则优先级更高。确认EnvironmentRepository的@Service注解是否生效,以及是否与手动绑定存在冲突。
内容的提问来源于stack exchange,提问作者Germán C. Basisty
相关产品推荐
相关产品推荐

