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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-16 05:50:55  来源:igfitidea点击:

Dependency injection with Jersey 2.0

javadependency-injectionjerseyjersey-2.0hk2

提问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 AbstractBinderand 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 @Injectis detected on a parameter or field of type MyService.classit 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 MyApplicationclass (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 并且你不想声明所有的绑定,你也可以试试这个适配器:

guice-bridge-jit-injector

guice-bridge-jit-injector

回答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 RequestScopedavailable

还有一个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 AbstractBinderimplementation 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 @Providerannotation should allow the Featureto be picked up by the package scanning. Or without package scanning, you can explicitly register the Featurein the web.xml

@Provider注释应允许Feature由包扫描被拾起。或者不用包扫描,你可以Featureweb.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:

也可以看看:

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 MyServiceinto 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 SomeManagedBeanis an ApplicationScoped bean.

就我而言,它SomeManagedBean是一个 ApplicationScoped bean。

Hope this helps to anyone.

希望这对任何人都有帮助。

回答by jansohn

For me it works without the AbstractBinderif 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() {