Java Jersey 2.0 的依赖注入
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16216759/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Dependency injection with Jersey 2.0
提问by donnie_armstrong
Starting from scratch without any previous Jersey 1.x knowledge, I'm having a hard time understanding how to setup dependency injection in my Jersey 2.0 project.
在没有任何先前 Jersey 1.x 知识的情况下从头开始,我很难理解如何在我的 Jersey 2.0 项目中设置依赖注入。
I also understand that HK2 is available in Jersey 2.0, but I cannot seem to find docs that help with Jersey 2.0 integration.
我也知道 HK2 在 Jersey 2.0 中可用,但我似乎找不到有助于 Jersey 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
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>
I can get the container to start and serve up my resource, but as soon as I add @Inject to MyService, the framework throws an exception:
我可以让容器启动并提供我的资源,但是一旦我将 @Inject 添加到 MyService,框架就会抛出异常:
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)
My starter project is available at GitHub: https://github.com/donaldjarmstrong/jaxrs
我的入门项目可在 GitHub 上找到:https: //github.com/donaldjarmstrong/jaxrs
采纳答案by joscarsson
You need to define an AbstractBinder
and register it in your JAX-RS application. The binder specifies how the dependency injection should create your classes.
您需要定义一个AbstractBinder
并将其注册到您的 JAX-RS 应用程序中。活页夹指定依赖注入应该如何创建您的类。
public class MyApplicationBinder extends AbstractBinder {
@Override
protected void configure() {
bind(MyService.class).to(MyService.class);
}
}
When @Inject
is detected on a parameter or field of type MyService.class
it is instantiated using the class MyService
. To use this binder, it need to be registered with the JAX-RS application. In your web.xml
, define a JAX-RS application like this:
当@Inject
在参数或类型字段上检测到时,MyService.class
它会使用类进行实例化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>
Implement the MyApplication
class (specified above in the init-param
).
实现MyApplication
类(在上面的 中指定init-param
)。
public class MyApplication extends ResourceConfig {
public MyApplication() {
register(new MyApplicationBinder());
packages(true, "com.mypackage.rest");
}
}
The binder specifying dependency injection is registered in the constructor of the class, and we also tell the application where to find the REST resources (in your case, MyResource
) using the packages()
method call.
指定依赖注入的绑定器在类的构造函数中注册,我们还MyResource
使用packages()
方法调用告诉应用程序在哪里可以找到 REST 资源(在您的情况下,)。
回答by Benjamin Mesing
Oracle recommends to add the @Path annotation to all types to be injected when combining JAX-RS with CDI: http://docs.oracle.com/javaee/7/tutorial/jaxrs-advanced004.htmThough this is far from perfect (e.g. you will get warning from Jersey on startup), I decided to take this route, which saves me from maintaining all supported types within a binder.
Oracle 建议在将 JAX-RS 与 CDI 结合时将@Path 注释添加到要注入的所有类型:http: //docs.oracle.com/javaee/7/tutorial/jaxrs-advanced004.htm虽然这远非完美(例如,您将在启动时收到 Jersey 的警告),我决定采用这条路线,这样我就不必在活页夹中维护所有支持的类型。
Example:
例子:
@Singleton
@Path("singleton-configuration-service")
public class ConfigurationService {
..
}
@Path("my-path")
class MyProvider {
@Inject ConfigurationService _configuration;
@GET
public Object get() {..}
}
回答by Choi
If you prefer to use Guice and you don't want to declare all the bindings, you can also try this adapter:
如果你更喜欢使用 Guice 并且你不想声明所有的绑定,你也可以试试这个适配器:
回答by otonglet
The selected answer dates from a while back. It is not practical to declare every binding in a custom HK2 binder. I'm using Tomcat and I just had to add one dependency. Even though it was designed for Glassfish it fits perfectly into other containers.
选定的答案可以追溯到很久以前。在自定义 HK2 绑定器中声明每个绑定是不切实际的。我正在使用 Tomcat,我只需要添加一个依赖项。即使它是为 Glassfish 设计的,它也可以完美地放入其他容器中。
<dependency>
<groupId>org.glassfish.jersey.containers.glassfish</groupId>
<artifactId>jersey-gf-cdi</artifactId>
<version>${jersey.version}</version>
</dependency>
Make sure your container is properly configured too (see the documentation).
确保您的容器也已正确配置(请参阅文档)。
回答by Paul Samsotha
First just to answer a comment in the accepts answer.
首先只是在接受答案中回答评论。
"What does bind do? What if I have an interface and an implementation?"
“绑定有什么作用?如果我有一个接口和一个实现怎么办?”
It simply reads bind( implementation ).to( contract )
. You can alternative chain .in( scope )
. Default scope of PerLookup
. So if you want a singleton, you can
它只是读取bind( implementation ).to( contract )
. 你可以替代链.in( scope )
。的默认范围PerLookup
。所以如果你想要一个单身人士,你可以
bind( implementation ).to( contract ).in( Singleton.class );
There's also a RequestScoped
available
还有一个RequestScoped
可用
Also, instead of bind(Class).to(Class)
, you can also bind(Instance).to(Class)
, which will be automatically be a singleton.
此外,除了 ,bind(Class).to(Class)
您还可以bind(Instance).to(Class)
,这将自动成为单例。
Adding to the accepted answer
添加到接受的答案
For those trying to figure out how to register your AbstractBinder
implementation in your web.xml (i.e. you're not using a ResourceConfig
), it seems the binder won't be discovered through package scanning, i.e.
对于那些试图弄清楚如何AbstractBinder
在您的 web.xml 中注册您的实现的人(即您没有使用 a 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>
Or this either
或者这个
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>
com.foo.YourBinderImpl
</param-value>
</init-param>
To get it to work, I had to implement a Feature
:
为了让它工作,我必须实现一个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;
}
}
The @Provider
annotation should allow the Feature
to be picked up by the package scanning. Or without package scanning, you can explicitly register the Feature
in the web.xml
该@Provider
注释应允许Feature
由包扫描被拾起。或者不用包扫描,你可以Feature
在web.xml
<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>
See Also:
也可以看看:
- Custom Method Parameter Injection with Jersey
- How to inject an object into jersey request context?
- How do I properly configure an EntityManager in a jersey / hk2 application?
- Request Scoped Injection into Singletons
and for general information from the Jersey documentation
以及来自泽西岛文档的一般信息
UPDATE
更新
Factories
工厂
Aside from the basic binding in the accepted answer, you also have factories, where you can have more complex creation logic, and also have access to request context information. For example
除了接受的答案中的基本绑定之外,您还有工厂,您可以在其中拥有更复杂的创建逻辑,并且还可以访问请求上下文信息。例如
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);
}
});
Then you can inject MyService
into your resource class.
然后你可以注入MyService
你的资源类。
回答by gjijon
Late but I hope this helps someone.
迟到了,但我希望这对某人有所帮助。
I have my JAX RS defined like this:
我的 JAX RS 定义如下:
@Path("/examplepath")
@RequestScoped //this make the diference
public class ExampleResource {
Then, in my code finally I can inject:
然后,在我的代码中,我终于可以注入:
@Inject
SomeManagedBean bean;
In my case, the SomeManagedBean
is an ApplicationScoped bean.
就我而言,它SomeManagedBean
是一个 ApplicationScoped bean。
Hope this helps to anyone.
希望这对任何人都有帮助。
回答by jansohn
For me it works without the AbstractBinder
if I include the following dependencies in my web application (running on Tomcat 8.5, Jersey 2.27):
对我来说,AbstractBinder
如果我在我的 Web 应用程序中包含以下依赖项(在 Tomcat 8.5、Jersey 2.27 上运行),它就可以工作:
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>${jersey-version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.ext.cdi</groupId>
<artifactId>jersey-cdi1x</artifactId>
<version>${jersey-version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
<version>${jersey-version}</version>
</dependency>
It works with CDI 1.2 / CDI 2.0 for me (using Weld 2 / 3 respectively).
它适用于我的 CDI 1.2 / CDI 2.0(分别使用 Weld 2 / 3)。
回答by alokj
Dependency required for jersey restful service and Tomcat is the server. where ${jersey.version} is 2.29.1
jersey restful 服务需要依赖,Tomcat 是服务器。其中 ${jersey.version} 是 2.29.1
<dependency>
<groupId>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
<version>2.0.SP1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-server</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
<version>${jersey.version}</version>
</dependency>
The basic code will be as follows:
基本代码如下:
@RequestScoped
@Path("test")
public class RESTEndpoint {
@GET
public String getMessage() {