Java 泽西HK2依赖注入

Java 泽西HK2依赖注入,java,rest,dependency-injection,jersey-2.0,hk2,Java,Rest,Dependency Injection,Jersey 2.0,Hk2,我正在编写一个简单的微服务来公开RESTAPI。所以我开始使用Jersey,当然我需要将我的对象注入Jersey资源。基本上,我有两个类定义了一组资源,其中一些需要使用另一个服务 所以基本上我有: public interface MyService { String getServiceName(); void doService(); } 此接口的2个实现(MyServiceBean和MyAlternativeServiceBean) 就我阅读泽西文件的理解而言,我定义了hk2活页夹:

我正在编写一个简单的微服务来公开RESTAPI。所以我开始使用Jersey,当然我需要将我的对象注入Jersey资源。基本上,我有两个类定义了一组资源,其中一些需要使用另一个服务

所以基本上我有:

public interface MyService {

String getServiceName();

void doService();
}

此接口的2个实现(MyServiceBean和MyAlternativeServiceBean)

就我阅读泽西文件的理解而言,我定义了hk2活页夹:

public class MyBinder implements Binder{

@Override
public void bind(DynamicConfiguration config) {

    DescriptorImpl descriptor = BuilderHelper.link(MyServiceBean.class).named("MyServiceBean").to(MyService.class).build();
    config.bind(descriptor);


    config.bind(BuilderHelper.link(MyAlternativeServiceBean.class).named("MyAlternativeServiceBean").to(MyService.class).build());

}
我已将此活页夹注册到ApplicationConfig类

public class ApplicationConfig extends ResourceConfig{

public ApplicationConfig(){
    property("property.value", "MyAlternativeServiceImplementation");
    registerInstances(new MyBinder());
}
}

并正确地注释到参考资料中

@Path("first")
    public class First {

        @Inject @Named(value = "MyServiceBean")
        private MyService myService;
    //...
    }

    @Path("second")
    public class Second {

        @Inject @Named(value = "MyAlternativeServiceBean")
        private MyService myService;
    //...
    }
在MyService实现之前的所有工作都没有args构造函数。但在1种情况下,我还需要为我的AlternativeServiceBean提供一个依赖项

这是构造函数

@Inject @Named("property.value")
    public MyAlternativeServiceBean(String property){
        this.property = property;
    }
但我有一个例外:

javax.servlet.ServletException: A MultiException has 5 exceptions.  They are:|1. org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at Injectee(requiredType=String,parent=MyAlternativeServiceBean,qualifiers={}),position=0,optional=false,self=false,unqualified=null,2080509613)|2. java.lang.IllegalArgumentException: While attempting to resolve the dependencies of com.hpe.services.MyAlternativeServiceBean errors were found|3. java.lang.IllegalStateException: Unable to perform operation: resolve on com.hpe.services.MyAlternativeServiceBean|4. java.lang.IllegalArgumentException: While attempting to resolve the dependencies of com.hpe.tests.SecondEntryPoint errors were found|5. java.lang.IllegalStateException: Unable to perform operation: resolve on com.hpe.tests.SecondEntryPoint|
    at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:392)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:381)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:344)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:219)
    at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:684)
    at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:501)
    at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:229)
    at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1086)
    at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:427)
    at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:193)
    at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1020)
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:135)
    at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:116)
    at org.eclipse.jetty.server.Server.handle(Server.java:370)
    at org.eclipse.jetty.server.AbstractHttpConnection.handleRequest(AbstractHttpConnection.java:494)
    at org.eclipse.jetty.server.AbstractHttpConnection.headerComplete(AbstractHttpConnection.java:973)
    at org.eclipse.jetty.server.AbstractHttpConnection$RequestHandler.headerComplete(AbstractHttpConnection.java:1035)
    at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:641)
    at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:231)
    at org.eclipse.jetty.server.AsyncHttpConnection.handle(AsyncHttpConnection.java:82)
    at org.eclipse.jetty.io.nio.SelectChannelEndPoint.handle(SelectChannelEndPoint.java:696)
    at org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run(SelectChannelEndPoint.java:53)
    at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:608)
    at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:543)
    at java.lang.Thread.run(Thread.java:745)
基本上,我不知道如何在hk2中注入属性/常量(例如,我可以从配置文件中读取)

谢谢


关于

您可以做的是创建自定义注释

@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface Config {
    String value();
}
然后为它创建一个
InjectionResolver
(允许使用自定义注释进行注入)

这是一个完整的测试用例

import org.glassfish.hk2.api.Injectee;
import org.glassfish.hk2.api.InjectionResolver;
import org.glassfish.hk2.api.ServiceHandle;
import org.glassfish.hk2.api.TypeLiteral;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.filter.LoggingFilter;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;

import javax.inject.Inject;
import javax.inject.Singleton;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;
import java.lang.annotation.*;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;

import static org.junit.Assert.*;

/**
 * Run like any other JUnit Test. Only one required dependency
 *
 * <dependency>
 *   <groupId>org.glassfish.jersey.test-framework.providers</groupId>
 *   <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
 *   <version>${jersey2.version}</version>
 * </dependency>
 *
 * @author Paul Samsotha
 */
public class ConfigExample extends JerseyTest {

    @Target({ElementType.FIELD, ElementType.PARAMETER})
    @Retention(RetentionPolicy.RUNTIME)
    public static @interface Config {
        String value();
    }

    public static class ConfigInjectionResolver implements InjectionResolver<Config> {

        private static final Map<String, String> properties = new HashMap<>();

        public ConfigInjectionResolver() {
            properties.put("greeting.message", "Hello World");
        }

        @Override
        public Object resolve(Injectee injectee, ServiceHandle<?> handle) {
            if (String.class == injectee.getRequiredType()) {
                AnnotatedElement elem = injectee.getParent();
                if (elem instanceof Constructor) {
                    Constructor ctor = (Constructor) elem;
                    Config config = (Config) ctor.getParameterAnnotations()[injectee.getPosition()][0];
                    return properties.get(config.value());
                } else {
                    Config config = elem.getAnnotation(Config.class);
                    return properties.get(config.value());
                }
            }
            return null;
        }

        @Override
        public boolean isConstructorParameterIndicator() { return true; }

        @Override
        public boolean isMethodParameterIndicator() { return false; }
    }


    private static interface GreetingService {
        String getGreeting();
    }

    private static class ConfiguredGreetingService implements GreetingService {
        private String message;

        public ConfiguredGreetingService(@Config("greeting.message") String message) {
            this.message = message;
        }

        @Override
        public String getGreeting() {
            return this.message;
        }
    }

    @Path("greeting")
    public static class GreetingResource {

        @Inject
        private GreetingService greetingService;

        @GET
        public String getConfigProp() {
            return greetingService.getGreeting();
        }
    }

    @Override
    public ResourceConfig configure() {
        ResourceConfig config = new ResourceConfig(GreetingResource.class);
        config.register(new LoggingFilter(Logger.getAnonymousLogger(), true));
        config.register(new AbstractBinder(){
            @Override
            protected void configure() {
                bind(ConfiguredGreetingService.class).to(GreetingService.class).in(Singleton.class);
                bind(ConfigInjectionResolver.class)
                        .to(new TypeLiteral<InjectionResolver<Config>>(){})
                        .in(Singleton.class);
            }
        });
        return config;
    }

    @Test
    public void should_get_configured_greeting() {
        final Response response = target("greeting")
                .request().get();
        assertEquals("Hello World", response.readEntity(String.class));
    }
}
import org.glassfish.hk2.api.Injectee;
导入org.glassfish.hk2.api.InjectionResolver;
导入org.glassfish.hk2.api.ServiceHandle;
导入org.glassfish.hk2.api.TypeLiteral;
导入org.glassfish.hk2.utilities.binding.AbstractBinder;
导入org.glassfish.jersey.filter.LoggingFilter;
导入org.glassfish.jersey.server.ResourceConfig;
导入org.glassfish.jersey.test.JerseyTest;
导入org.junit.Test;
导入javax.inject.inject;
导入javax.inject.Singleton;
导入javax.ws.rs.GET;
导入javax.ws.rs.Path;
导入javax.ws.rs.core.Response;
导入java.lang.annotation.*;
导入java.lang.reflect.AnnotateDelete;
导入java.lang.reflect.Constructor;
导入java.util.HashMap;
导入java.util.Map;
导入java.util.logging.Logger;
导入静态org.junit.Assert.*;
/**
*像其他JUnit测试一样运行。只需要一个依赖项
*
* 
*org.glassfish.jersey.test-framework.providers
*jersey-test-framework-provider-grizzly2
*${jersey2.version}
* 
*
*@作者保罗·桑索塔
*/
公共类ConfigExample扩展了JerseyTest{
@目标({ElementType.FIELD,ElementType.PARAMETER})
@保留(RetentionPolicy.RUNTIME)
公共静态@接口配置{
字符串值();
}
公共静态类ConfigInjectionResolver实现InjectionResolver{
私有静态最终映射属性=new HashMap();
公共ConfigInjectionResolver(){
properties.put(“greeting.message”、“Hello World”);
}
@凌驾
公共对象解析(注入对象、注入对象、ServiceHandle){
if(String.class==injectee.getRequiredType()){
AnnotatedElement elem=injectee.getParent();
if(构造函数的元素实例){
构造函数ctor=(构造函数)元素;
Config Config=(Config)ctor.getParameterAnnotations()[injectee.getPosition()][0];
返回properties.get(config.value());
}否则{
Config=elem.getAnnotation(Config.class);
返回properties.get(config.value());
}
}
返回null;
}
@凌驾
公共布尔值isConstructorParameterIndicator(){return true;}
@凌驾
公共布尔值isMethodParameterIndicator(){return false;}
}
专用静态接口欢迎服务{
字符串getGreeting();
}
私有静态类ConfiguredGreetingService实现GreetingService{
私有字符串消息;
公共配置的greetingservice(@Config(“greeting.message”)字符串消息){
this.message=消息;
}
@凌驾
公共字符串getGreeting(){
返回此消息;
}
}
@路径(“问候语”)
公共静态类问候资源{
@注入
私人迎宾服务迎宾服务;
@得到
公共字符串getConfigProp(){
return greetingService.getGreeting();
}
}
@凌驾
公共资源配置(){
ResourceConfig=newResourceConfig(GreetingResource.class);
config.register(新的LoggingFilter(Logger.getAnonymousLogger(),true));
config.register(新的AbstractBinder(){
@凌驾
受保护的void configure(){
绑定(ConfiguredGreetingService.class).to(GreetingService.class).in(Singleton.class);
绑定(ConfigInjectionResolver.class)
.to(新的TypeLiteral(){})
.在(独生子女班);
}
});
返回配置;
}
@试验
public void应该\u配置\u问候语(){
最终响应=目标(“问候语”)
.request().get();
assertEquals(“helloworld”,response.readEntity(String.class));
}
}

构造函数是什么样子的?您认为这些构造函数argummts来自哪里?我想知道如何将jersey与hk2完全集成:我的意思是hk2可以为我构建对象,然后将这些对象注入jersey资源(当然也可以在需要时注入其他对象)。目前我不知道如何告诉hk2创建两个单例“MyServiceBean”和“MyAlternativeServiceBean”。我在考虑spring的方式,框架基本上为我构建对象,并将这些对象保存在AppContext中。不确定你得到了什么。错误告诉您,它找不到合适的构造函数,因为您添加了不适合注入点的构造函数参数,即您没有要注入到构造函数的服务,或者您没有使用
@inject
将构造函数标记为注入点。这没什么不同
public SomeService(@Config("some.property") String property) {}
import org.glassfish.hk2.api.Injectee;
import org.glassfish.hk2.api.InjectionResolver;
import org.glassfish.hk2.api.ServiceHandle;
import org.glassfish.hk2.api.TypeLiteral;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.filter.LoggingFilter;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;

import javax.inject.Inject;
import javax.inject.Singleton;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;
import java.lang.annotation.*;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;

import static org.junit.Assert.*;

/**
 * Run like any other JUnit Test. Only one required dependency
 *
 * <dependency>
 *   <groupId>org.glassfish.jersey.test-framework.providers</groupId>
 *   <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
 *   <version>${jersey2.version}</version>
 * </dependency>
 *
 * @author Paul Samsotha
 */
public class ConfigExample extends JerseyTest {

    @Target({ElementType.FIELD, ElementType.PARAMETER})
    @Retention(RetentionPolicy.RUNTIME)
    public static @interface Config {
        String value();
    }

    public static class ConfigInjectionResolver implements InjectionResolver<Config> {

        private static final Map<String, String> properties = new HashMap<>();

        public ConfigInjectionResolver() {
            properties.put("greeting.message", "Hello World");
        }

        @Override
        public Object resolve(Injectee injectee, ServiceHandle<?> handle) {
            if (String.class == injectee.getRequiredType()) {
                AnnotatedElement elem = injectee.getParent();
                if (elem instanceof Constructor) {
                    Constructor ctor = (Constructor) elem;
                    Config config = (Config) ctor.getParameterAnnotations()[injectee.getPosition()][0];
                    return properties.get(config.value());
                } else {
                    Config config = elem.getAnnotation(Config.class);
                    return properties.get(config.value());
                }
            }
            return null;
        }

        @Override
        public boolean isConstructorParameterIndicator() { return true; }

        @Override
        public boolean isMethodParameterIndicator() { return false; }
    }


    private static interface GreetingService {
        String getGreeting();
    }

    private static class ConfiguredGreetingService implements GreetingService {
        private String message;

        public ConfiguredGreetingService(@Config("greeting.message") String message) {
            this.message = message;
        }

        @Override
        public String getGreeting() {
            return this.message;
        }
    }

    @Path("greeting")
    public static class GreetingResource {

        @Inject
        private GreetingService greetingService;

        @GET
        public String getConfigProp() {
            return greetingService.getGreeting();
        }
    }

    @Override
    public ResourceConfig configure() {
        ResourceConfig config = new ResourceConfig(GreetingResource.class);
        config.register(new LoggingFilter(Logger.getAnonymousLogger(), true));
        config.register(new AbstractBinder(){
            @Override
            protected void configure() {
                bind(ConfiguredGreetingService.class).to(GreetingService.class).in(Singleton.class);
                bind(ConfigInjectionResolver.class)
                        .to(new TypeLiteral<InjectionResolver<Config>>(){})
                        .in(Singleton.class);
            }
        });
        return config;
    }

    @Test
    public void should_get_configured_greeting() {
        final Response response = target("greeting")
                .request().get();
        assertEquals("Hello World", response.readEntity(String.class));
    }
}