泽西HK2依赖注射

我正在编写一个公开REST API的简单微服务。 所以我开始与泽西岛合作,当然我需要将我的对象注入jersey资源。 基本上我有2个类定义了一组资源,其中一些需要使用另一个服务。

基本上我有:

public interface MyService { String getServiceName(); void doService(); 

}

此接口的2个实现(MyServiceBean和MyAlternativeServiceBean)

而且,据我所知阅读jersey文件,我定义了一个hk2 Binder:

 public class MyBinder implements Binder{ @Override public void bind(DynamicConfiguration config) { DescriptorImpl descriptor = BuilderHelper.link(MyServiceBean.class).named("MyServiceBean").to(MyService.class).build(); config.bind(descriptor); config.bind(BuilderHelper.link(MyAlternativeServiceBean.class).named("MyAlternativeServiceBean").to(MyService.class).build()); } 

我将此绑定程序注册到ApplicationConfig类

 public class ApplicationConfig extends ResourceConfig{ public ApplicationConfig(){ property("property.value", "MyAlternativeServiceImplementation"); registerInstances(new MyBinder()); } 

}

并正确注释到资源中

 @Path("first") public class First { @Inject @Named(value = "MyServiceBean") private MyService myService; //... } @Path("second") public class Second { @Inject @Named(value = "MyAlternativeServiceBean") private MyService myService; //... } 

一直有效,直到MyService实现没有args构造函数。 但在一种情况下,我还需要为MyAlternativeServiceBean提供依赖。

这是构造函数

 @Inject @Named("property.value") public MyAlternativeServiceBean(String property){ this.property = property; } 

但我得到一个例外:

 javax.servlet.ServletException: A MultiException has 5 exceptions. They are:|1. org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at Injectee(requiredType=String,parent=MyAlternativeServiceBean,qualifiers={}),position=0,optional=false,self=false,unqualified=null,2080509613)|2. java.lang.IllegalArgumentException: While attempting to resolve the dependencies of com.hpe.services.MyAlternativeServiceBean errors were found|3. java.lang.IllegalStateException: Unable to perform operation: resolve on com.hpe.services.MyAlternativeServiceBean|4. java.lang.IllegalArgumentException: While attempting to resolve the dependencies of com.hpe.tests.SecondEntryPoint errors were found|5. java.lang.IllegalStateException: Unable to perform operation: resolve on com.hpe.tests.SecondEntryPoint| at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:392) at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:381) at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:344) at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:219) at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:684) at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:501) at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:229) at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1086) at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:427) at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:193) at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1020) at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:135) at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:116) at org.eclipse.jetty.server.Server.handle(Server.java:370) at org.eclipse.jetty.server.AbstractHttpConnection.handleRequest(AbstractHttpConnection.java:494) at org.eclipse.jetty.server.AbstractHttpConnection.headerComplete(AbstractHttpConnection.java:973) at org.eclipse.jetty.server.AbstractHttpConnection$RequestHandler.headerComplete(AbstractHttpConnection.java:1035) at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:641) at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:231) at org.eclipse.jetty.server.AsyncHttpConnection.handle(AsyncHttpConnection.java:82) at org.eclipse.jetty.io.nio.SelectChannelEndPoint.handle(SelectChannelEndPoint.java:696) at org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run(SelectChannelEndPoint.java:53) at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:608) at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:543) at java.lang.Thread.run(Thread.java:745) 

基本上我不知道如何在hk2中注入属性/常量(我可以从配置文件中读取)

谢谢

问候

您可以做的是创建自定义注释

 @Target({ElementType.FIELD, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) public @interface Config { String value(); } 

然后为它创建一个InjectionResolver (允许使用自定义注释进行注入)

 public static class ConfigInjectionResolver implements InjectionResolver { private static final Map properties = new HashMap<>(); public ConfigInjectionResolver() { properties.put("greeting.message", "Hello World"); } @Override public Object resolve(Injectee injectee, ServiceHandle handle) { if (String.class == injectee.getRequiredType()) { AnnotatedElement elem = injectee.getParent(); if (elem instanceof Constructor) { Constructor ctor = (Constructor) elem; Config config = (Config) ctor.getParameterAnnotations()[injectee.getPosition()][0]; return properties.get(config.value()); } else { Config config = elem.getAnnotation(Config.class); return properties.get(config.value()); } } return null; } @Override public boolean isConstructorParameterIndicator() { return true; } @Override public boolean isMethodParameterIndicator() { return false; } } 

这个例子只使用了Map ,但我相信你可以弄清楚如何让它使用Properties 。 注册InjectionResolver ,您现在就可以了

 public SomeService(@Config("some.property") String property) {} 

这是一个完整的测试用例

 import org.glassfish.hk2.api.Injectee; import org.glassfish.hk2.api.InjectionResolver; import org.glassfish.hk2.api.ServiceHandle; import org.glassfish.hk2.api.TypeLiteral; import org.glassfish.hk2.utilities.binding.AbstractBinder; import org.glassfish.jersey.filter.LoggingFilter; import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.test.JerseyTest; import org.junit.Test; import javax.inject.Inject; import javax.inject.Singleton; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.core.Response; import java.lang.annotation.*; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Constructor; import java.util.HashMap; import java.util.Map; import java.util.logging.Logger; import static org.junit.Assert.*; /** * Run like any other JUnit Test. Only one required dependency * *  * org.glassfish.jersey.test-framework.providers * jersey-test-framework-provider-grizzly2 * ${jersey2.version} *  * * @author Paul Samsotha */ public class ConfigExample extends JerseyTest { @Target({ElementType.FIELD, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) public static @interface Config { String value(); } public static class ConfigInjectionResolver implements InjectionResolver { private static final Map properties = new HashMap<>(); public ConfigInjectionResolver() { properties.put("greeting.message", "Hello World"); } @Override public Object resolve(Injectee injectee, ServiceHandle handle) { if (String.class == injectee.getRequiredType()) { AnnotatedElement elem = injectee.getParent(); if (elem instanceof Constructor) { Constructor ctor = (Constructor) elem; Config config = (Config) ctor.getParameterAnnotations()[injectee.getPosition()][0]; return properties.get(config.value()); } else { Config config = elem.getAnnotation(Config.class); return properties.get(config.value()); } } return null; } @Override public boolean isConstructorParameterIndicator() { return true; } @Override public boolean isMethodParameterIndicator() { return false; } } private static interface GreetingService { String getGreeting(); } private static class ConfiguredGreetingService implements GreetingService { private String message; public ConfiguredGreetingService(@Config("greeting.message") String message) { this.message = message; } @Override public String getGreeting() { return this.message; } } @Path("greeting") public static class GreetingResource { @Inject private GreetingService greetingService; @GET public String getConfigProp() { return greetingService.getGreeting(); } } @Override public ResourceConfig configure() { ResourceConfig config = new ResourceConfig(GreetingResource.class); config.register(new LoggingFilter(Logger.getAnonymousLogger(), true)); config.register(new AbstractBinder(){ @Override protected void configure() { bind(ConfiguredGreetingService.class).to(GreetingService.class).in(Singleton.class); bind(ConfigInjectionResolver.class) .to(new TypeLiteral>(){}) .in(Singleton.class); } }); return config; } @Test public void should_get_configured_greeting() { final Response response = target("greeting") .request().get(); assertEquals("Hello World", response.readEntity(String.class)); } }