使用泽西岛 2.0 进行依赖注入

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

我也知道HK2在泽西岛2.0中可用,但我似乎找不到有助于泽西岛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");
    }
}

啪.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>

我可以让容器启动并提供我的资源,但是一旦我向MyService添加@Inject,框架就会引发异常:

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


答案 1

您需要定义一个并在 JAX-RS 应用程序中注册它。绑定程序指定依赖关系注入应如何创建类。AbstractBinder

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

当在类型的参数或字段上检测到 时,将使用类 实例化它。要使用此绑定器,需要向 JAX-RS 应用程序注册它。在 中,定义一个 JAX-RS 应用程序,如下所示:@InjectMyService.classMyServiceweb.xml

<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>

实现该类(在上面的 中指定)。MyApplicationinit-param

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

指定依赖关系注入的绑定器在类的构造函数中注册,我们还使用方法调用告诉应用程序在哪里可以找到 REST 资源(在你的例子中为 )。MyResourcepackages()


答案 2

首先,只需回答接受答案中的注释。

“绑定有什么作用?如果我有一个接口和一个实现呢?

它只是简单地读取.你可以替代链。的默认作用域 。所以如果你想要一个单例,你可以bind( implementation ).to( contract ).in( scope )PerLookup

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

还有一个可用的RequestScoped

此外,您也可以代替 ,它将自动成为单例。bind(Class).to(Class)bind(Instance).to(Class)


添加到接受的答案

对于那些试图弄清楚如何在Web中注册您的实现.xml(即您没有使用a)的人来说,似乎不会通过包扫描发现活页夹,即AbstractBinderResourceConfig

<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>

为了让它工作,我必须实现一个功能

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;
    }
}

注释应允许包扫描拾取 。或者无需包扫描,您可以在@ProviderFeatureFeatureweb.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>

另请参阅:

以及泽西岛文档中的一般信息


更新

工厂

除了接受的答案中的基本绑定之外,您还有工厂,您可以在其中拥有更复杂的创建逻辑,还可以访问请求上下文信息。例如

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


推荐