泽西岛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.class
types的参数或字段上检测到@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注射器