泽西岛2.0的dependency injection

从头开始,没有任何以前的泽西岛1.x的知识,我很难理解如何在我的Jersey 2.0项目中设置依赖项注入。

我也明白HK2可以在泽西岛2.0,但我似乎无法find有助于泽西岛2.0集成的文件。

@ManagedBean @Path("myresource") public class MyResource { @Inject MyService myService; /** * Method handling HTTP GET requests. The returned object will be sent * to the client as "text/plain" media type. * * @return String that will be returned as a text/plain response. */ @GET @Produces(MediaType.APPLICATION_JSON) @Path("/getit") public String getIt() { return "Got it {" + myService + "}"; } } @Resource @ManagedBean public class MyService { void serviceCall() { System.out.print("Service calls"); } } 

的pom.xml

 <properties> <jersey.version>2.0-rc1</jersey.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.glassfish.jersey</groupId> <artifactId>jersey-bom</artifactId> <version>${jersey.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.glassfish.jersey.core</groupId> <artifactId>jersey-common</artifactId> </dependency> <dependency> <groupId>org.glassfish.jersey.core</groupId> <artifactId>jersey-server</artifactId> </dependency> <dependency> <groupId>org.glassfish.jersey</groupId> <artifactId>jax-rs-ri</artifactId> </dependency> </dependencies> 

我可以让容器启动并提供我的资源,但只要将@Inject添加到MyService,框架就会引发exception:

 SEVERE: Servlet.service() for servlet [com.noip.MyApplication] in context with path [/jaxrs] threw exception [A MultiException has 3 exceptions. They are: 1. org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at Injectee(requiredType=MyService,parent=MyResource,qualifiers={}),position=-1,optional=false,self=false,unqualified=null,1039471128) 2. java.lang.IllegalArgumentException: While attempting to resolve the dependencies of com.noip.MyResource errors were found 3. java.lang.IllegalStateException: Unable to perform operation: resolve on com.noip.MyResource ] with root cause org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at Injectee(requiredType=MyService,parent=MyResource,qualifiers={}),position=-1,optional=false,self=false,unqualified=null,1039471128) at org.jvnet.hk2.internal.ThreeThirtyResolver.resolve(ThreeThirtyResolver.java:74) 

我的初学者项目可在GitHub: https : //github.com/donaldjarmstrong/jaxrs

您需要定义一个AbstractBinder并将其注册到您的JAX-RS应用程序中。 活页夹指定了dependency injection如何创build你的类。

 public class MyApplicationBinder extends AbstractBinder { @Override protected void configure() { bind(MyService.class).to(MyService.class); } } 

当在MyService.classtypes的参数或字段上检测到@Inject时,它将使用MyService类实例化。 要使用这个绑定,它需要注册到JAX-RS应用程序。 在你的web.xml ,像这样定义一个JAX-RS应用程序:

 <servlet> <servlet-name>MyApplication</servlet-name> <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class> <init-param> <param-name>javax.ws.rs.Application</param-name> <param-value>com.mypackage.MyApplication</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>MyApplication</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> 

实现MyApplication类(在init-param指定)。

 public class MyApplication extends ResourceConfig { public MyApplication() { register(new MyApplicationBinder()); packages(true, "com.mypackage.rest"); } } 

绑定器指定dependency injection是在类的构造函数中注册的,我们也通过使用packages()方法调用告诉应用程序在哪里findREST资源(在你的情况下是MyResource )。

首先回答接受答案中的评论。

“绑定是做什么的?如果我有一个接口和一个实现呢?

它只是读取bind( implementation ).to( contract ) 。 你可以select链.in( scope )PerLookup默认范围。 所以,如果你想要一个单身人士,你可以

 bind( implementation ).to( contract ).in( Singleton.class ); 

还有一个RequestScoped可用

另外,也可以bind(Instance).to(Class) ,而不是bind(Class).to(Class) ,它将自动成为一个单例。


添加到接受的答案

对于那些试图弄清楚如何在你的web.xml中注册你的AbstractBinder实现(即你没有使用ResourceConfig ),看起来绑定器不会被封装扫描发现,即

 <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class> <init-param> <param-name>jersey.config.server.provider.packages</param-name> <param-value> your.packages.to.scan </param-value> </init-param> 

或者这个

 <init-param> <param-name>jersey.config.server.provider.classnames</param-name> <param-value> com.foo.YourBinderImpl </param-value> </init-param> 

为了得到它的工作,我必须实现一个Feature

 import javax.ws.rs.core.Feature; import javax.ws.rs.core.FeatureContext; import javax.ws.rs.ext.Provider; @Provider public class Hk2Feature implements Feature { @Override public boolean configure(FeatureContext context) { context.register(new AppBinder()); return true; } } 

@Provider注释应该允许Feature被包扫描拾取。 或者,无需打包扫描,您可以在web.xml显式注册Feature

 <servlet> <servlet-name>Jersey Web Application</servlet-name> <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class> <init-param> <param-name>jersey.config.server.provider.classnames</param-name> <param-value> com.foo.Hk2Feature </param-value> </init-param> ... <load-on-startup>1</load-on-startup> </servlet> 

也可以看看:

  • 使用Jersey的自定义方法参数注入
  • 如何将对象注入jersey请求上下文?
  • 如何在泽西/ hk2应用程序中正确configuration一个EntityManager?
  • 请求范围注入单身人士

并从泽西岛文件的一般信息

  • 自定义注入和生命周期pipe理

UPDATE

工厂

除了被接受的答案中的基本绑定之外,你还有工厂,在那里你可以有更复杂的创build逻辑,并且也可以访问请求上下文信息。 例如

 public class MyServiceFactory implements Factory<MyService> { @Context private HttpHeaders headers; @Override public MyService provide() { return new MyService(headers.getHeaderString("X-Header")); } @Override public void dispose(MyService service) { /* noop */ } } register(new AbstractBinder() { @Override public void configure() { bindFactory(MyServiceFactory.class).to(MyService.class) .in(RequestScoped.class); } }); 

然后你可以注入MyService到你的资源类。

选定的答案date从前一阵子。 在自定义HK2联编程序中声明每个绑定是不实际的。 我正在使用Tomcat,我只需要添加一个依赖项。 尽pipe它是为Glassfishdevise的,但它完全适合其他容器。

  <dependency> <groupId>org.glassfish.jersey.containers.glassfish</groupId> <artifactId>jersey-gf-cdi</artifactId> <version>${jersey.version}</version> </dependency> 

确保您的容器也已正确configuration( 请参阅文档 )。

Oraclebuild议在将JAX-RS与CDI结合时将@Path注释添加到所有要注入的types中: http : //docs.oracle.com/javaee/7/tutorial/jaxrs-advanced004.htm虽然这远非完美比如你会在启动时收到泽西岛的警告),我决定采取这种方式,这样可以节省我在活页夹中维护所有支持的types。

例:

 @Singleton @Path("singleton-configuration-service") public class ConfigurationService { .. } @Path("my-path") class MyProvider { @Inject ConfigurationService _configuration; @GET public Object get() {..} } 

晚了,但我希望这有助于某人。

我有我的JAX RS定义如下:

 @Path("/examplepath") @RequestScoped //this make the diference public class ExampleResource { 

然后,在我的代码最后我可以注入:

 @Inject SomeManagedBean bean; 

在我的情况下, SomeManagedBean是一个ApplicationScoped bean。

希望这有助于任何人。

如果你喜欢使用Guice,并且你不想声明所有的绑定,你也可以试试这个适配器:

吉斯桥- JIT注射器