2016-12-31 9 views
2

Я пишу простой микросервис, который предоставляет REST API. Поэтому я начал работать с Джерси, и, конечно же, мне нужно включить объект в трикотажные ресурсы. В основном у меня есть 2 класса, которые определяют набор ресурсов, а некоторые из них должны использовать другую службу.Джерси HK2 Инъекция зависимостей

Поэтому в основном у меня есть:

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 случае мне нужно также обеспечить зависимость от MyAlternativeServiceBean.

Вот конструктор

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

В принципе я не konw, как придать свойства/константы (которые я могу читать из файла конфигурации для экземпляр) в ¯hk2

Благодарности

с уважением

+0

Что конструктор выглядит? Где вы ожидаете, что эти конструкторские аргументы будут поступать? –

+0

Я хотел бы знать, как я могу полностью интегрировать трикотаж с hk2: я имею в виду, что hk2 может создать объект для меня, а затем вставить этот объект в трикотажные ресурсы (и, конечно, в другие объекты там, где это необходимо). На данный момент я не знаю, как сказать hk2 создать 2 синглтона «MyServiceBean» и «MyAlternativeServiceBean».Я думаю, что весной, где в основном объекты построения каркаса для меня и хранят эти объекты в AppContext. – Raffaele

+1

Не уверен, что вы получаете. Ошибка говорит вам, что он не может найти подходящий конструктор, потому что вы добавили аргументы конструктора, которые не являются подходящими точками впрыска, то есть либо у вас нет служб для инъекции конструктору, либо вы не отметили конструктор как точку впрыска с '@ Inject'. Это не отличается от того, как работает Spring. Если вы пытаетесь создать аргументы конструктора и не помечены как точка впрыска с помощью '@ Autowired', или нет никаких компонентов для вставки, вы получите аналогичную ошибку. Это ничем не отличается. –

ответ

5

Что вы можете сделать, это создать пользовательский аннотацию

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

Затем создайте InjectionResolver для него (что позволяет нагнетательных с помощью пользовательских аннотаций)

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

Этот пример просто использует Map, но Я уверен, что вы можете понять, как сделать это Properties. После регистрации InjectionResolver, теперь вы можете просто сделать

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)); 
    } 
} 
+0

Большое спасибо! Он отлично работает! – Raffaele