无法使用内置的Jersey依赖注入在Jersey 2中创建一个简单的单例类

ric*_*icb 12 singleton dependency-injection jax-rs jersey-2.0 hk2

我无法使用Jersey 2(2.7)和Jersey内置的HK2依赖注入来实现一个非常基本的单例类实现.我在Tomcat上运行它.

我的目标是创建将由各种Web服务方法使用的支持类的单例实例.我没有强烈的偏好在构造函数注入,方法注入和注释类成员之间(如下所示).

这是我要成为的单身人士课程:

package singletest;

import javax.inject.Singleton;

@Singleton
public class JustOne {
    private int secretNumber = 0;

    public void hitMe(int input) {
        secretNumber += input;
    }

    @Override
    public String toString() {
        return String.format("{ \"secretNumber\": %s }", secretNumber);
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我的应用程序类:

package singletest;

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
import java.util.HashSet;
import java.util.Set;

@ApplicationPath("/*")
public class MainApplication extends Application {
    @Override
    public Set<Class<?>> getClasses() {
        Set<Class<?>> classes = new HashSet<>();
        classes.add(TestResource.class);
        return classes;
    }

    @Override
    public Set<Object> getSingletons() {
        Set<Object> singletons = new HashSet<>();
        singletons.add(new JustOneProvider());
        return singletons;
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我的Provider/ContextResolver类:

package singletest;

import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;

@Provider
public class JustOneProvider implements ContextResolver<JustOne> {
    private static JustOne justOne = new JustOne();

    @Override
    public JustOne getContext(Class<?> type) {
        return justOne;
    }
}
Run Code Online (Sandbox Code Playgroud)

web.xml中:

<?xml version="1.0" encoding="UTF-8"?>

<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <filter>
        <filter-name>singletest.MainApplication</filter-name>
        <filter-class>org.glassfish.jersey.servlet.ServletContainer</filter-class>
        <init-param>
            <param-name>javax.ws.rs.Application</param-name>
            <param-value>singletest.MainApplication</param-value>
        </init-param>
        <!-- pass to next filter if Jersey/App returns 404 -->
        <init-param>
            <param-name>jersey.config.servlet.filter.forwardOn404</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>singletest.MainApplication</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>
Run Code Online (Sandbox Code Playgroud)

我打算注入JustOne类的单例实例的资源:

package singletest;

import javax.inject.Inject;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

@Path("/test")
public class TestResource {

    @Inject
    private JustOne justOne;

    @GET
    @Consumes(MediaType.TEXT_PLAIN)
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/func1/{input}")
    public Response func1(@PathParam("input") int input) {
        justOne.hitMe(input);
        String responseData = justOne.toString();
        return Response.ok(responseData).build();
    }
}
Run Code Online (Sandbox Code Playgroud)

在Jersey中部署/初始化战争时会引发此警告:

Apr 28, 2014 11:48:25 AM org.glassfish.jersey.server.ApplicationHandler initialize
INFO: Initiating Jersey application, version Jersey: 2.7 ${buildNumber}...
Apr 28, 2014 11:48:25 AM org.glassfish.jersey.internal.inject.Providers checkProviderRuntime
WARNING: A provider java.lang.Class registered in SERVER runtime does not implement any provider interfaces applicable in the SERVER runtime. Due to constraint configuration problems the provider java.lang.Class will be ignored.
Run Code Online (Sandbox Code Playgroud)

我调用这个Web服务时得到的错误:

type Exception report

message A MultiException has 3 exceptions. They are:

description The server encountered an internal error that prevented it from fulfilling this request.

exception

javax.servlet.ServletException: A MultiException has 3 exceptions.  They are:
1. org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at Injectee(requiredType=JustOne,parent=TestResource,qualifiers={}),position=-1,optional=false,self=false,unqualified=null,58952407)
2. java.lang.IllegalArgumentException: While attempting to resolve the dependencies of singletest.TestResource errors were found
3. java.lang.IllegalStateException: Unable to perform operation: resolve on singletest.TestResource

    org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:333)
    org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:372)
    org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:335)
    org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:218)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
Run Code Online (Sandbox Code Playgroud)

所以,我明白了:hk2没有获得足够的信息来创建/绑定JustOne实例和/或查找/使用我的JustOneProvider.我确定我遗漏了一些基本的东西.任何指导将不胜感激.

小智 19

bind(JustOne.class).to(JustOne.class).in(Singleton.class);     
Run Code Online (Sandbox Code Playgroud)

是最重要的部分.如果没有"in(Singleton.class)",将创建JustOne的多个实例.

  • `bind(new JustOne()).to ...`是绑定_constant_的语法,而不是单例.确实只会创建一个"JustOne"实例,但它将由您手动创建,而不是由HK2创建.如果你的`JustOne`单例也需要注入依赖项,那么这两种形式之间的区别可能才会很重要. (4认同)
  • 我可以确认,这确实是您要由HK2本身注入单例实例而不是手动提供类实例时需要做的。 (2认同)

ric*_*icb 14

好吧,在花了一大笔时间在这上面后,我开始工作了.

我使用了HK2 AbstractBinder和JAX-RS功能(javax.ws.rs.core.Feature).

事实证明,不需要Provider/ContextResolver.

应用:

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
import java.util.HashSet;
import java.util.Set;

@ApplicationPath("/*")
public class MainApplication extends Application {

    @Override
    public Set<Class<?>> getClasses() {
        Set<Class<?>> classes = new HashSet<>();
        classes.add(TestResource.class);
        classes.add(JustOneFeature.class);
        return classes;
    }

}
Run Code Online (Sandbox Code Playgroud)

待单身类:

public class JustOne {
    private int secretNumber = 0;

    public int getSecretNumber() {
        return secretNumber;
    }

    public void bumpSecretNumber() {
        secretNumber += 1;
    }
}
Run Code Online (Sandbox Code Playgroud)

活页夹:

import org.glassfish.hk2.utilities.binding.AbstractBinder;

public class JustOneBinder extends AbstractBinder {
    @Override
    protected void configure() {
        bind(new JustOne()).to(JustOne.class);
    }
}
Run Code Online (Sandbox Code Playgroud)

特征:

import javax.ws.rs.core.Feature;
import javax.ws.rs.core.FeatureContext;

public class JustOneFeature implements Feature {

    @Override
    public boolean configure(final FeatureContext context) {
        context.register(new JustOneBinder());
        return true;
    }
}
Run Code Online (Sandbox Code Playgroud)

获取单例注入的资源:

import javax.inject.Inject;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

@Path("/test")
public class TestResource {

    @Inject
    private JustOne justOne;

    @GET
    @Consumes(MediaType.TEXT_PLAIN)
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/func1/{input}")
    public Response func1(@PathParam("input") int input) {
        justOne.bumpSecretNumber();
        String responseData = String.format("{ \"result\": %s }", input + justOne.getSecretNumber());
        return Response.ok(responseData).build();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 好吧,要使DI起作用,必须由DI框架自己创建具有Inject声明的类。如果使用“ new MyClass()”创建类实例(非资源类或资源类),则DI框架对此一无所知,而Inject将无法正常工作。HK2内置在Jersey中,因此它涉及创建Jersey类实例,例如资源类。这就是为什么Inject适用于那些人的原因。如果要将HK2 DI用于非Jersey创建的类,则必须弄清楚如何让HK2实例化包含Inject声明的类。 (2认同)