2016-09-20 5 views
1

Есть ли способ встраивать зависимости в созданные вручную объекты?Джерси Инъекция HK2 в создаваемых вручную объектах

public class MyCommand { 
    @Inject Repository repository; 
} 

public Repository { 
    @Inject EntityManager em; 
} 

MyCommand command = new MyCommand(); 

хранилище должным образом зарегистрирован Джерси ResourceConfig и может быть введено в объектах, которые создаются через контейнер CDI, например, класс ресурсов.

Но так как я сам создаю команду, аннотация @Inject игнорируется.

Есть ли способ получить зарегистрированный класс рядом с @Inject и @Context? Что-то вроде Application.get (Repository.class)

public class MyCommand { 
    Repository repository; 

    public MyCommand() { 
     repository = Application.get(Repository.class); 
    } 
} 

----- EDIT -----

Благодаря вашей помощи и некоторое переосмысление я нашел решение моей проблемы.

Первое, что можно внедрить ServiceLocator без каких-либо операций в объекты.

Во-вторых, я перешел из обычных команд с помощью метода execute в систему командной шины. Причина этого заключается в том, что у меня нет никакого контроля над созданием команд, поэтому есть чистый способ получить введенные зависимости.

Новый подход выглядит следующим образом:

class CommandBus { 
    private final ServiceLocator serviceLocator; 

    @Inject 
    public CommandBus(ServiceLocator serviceLocator) { 
     this.serviceLocator = serviceLocator; 
    } 

    public void dispatch(Command command) { 
     Class handlerClass = findHandlerClassForCommand(command); 
     CommandHandler handler = (CommandHandler) serviceLocator.getService(handlerClass); 
     handler.handle(command); 
    } 
} 

interface CommandHandler { 
    void handle(Command command); 
} 

interface Command { 
} 

class ConcreteCommand implements Command { 
    // I'm just a dto with getters and setters 
} 

class ConcreteHandler implements CommandHandler { 
    private final SomeDependency dependency; 

    @Inject 
    public ConcreteHandler(SomeDependency dependency) { 
     this.dependency = dependency; 
    } 
    @Override 
    public void handle(ConcreteCommand command) { 
     // do some things 
    } 
} 

И в моих ресурсов у меня есть что-то вроде этого:

@Path("/some-resource") 
class Resource { 

    @Context 
    private CommandBus bus; 

    @POST 
    @Consumes(MediaType.APPLICATION_JSON) 
    public void runCommand(ConcreteCommand command) { 
     bus.dispatch(command); 
    } 
} 
+0

Это возможно, однако я бы рекомендовал использовать мост в рамках впрыска общего назначения (например, Google Guice). Альтернативный вариант введения и связывания с трикотажем описан в моем ответе здесь: http://stackoverflow.com/questions/38976724/how-to-set-an-object-to-context-so-that-i-can-get-it- где-нибудь-в-приложении/39000866 # 39000866 – pandaadb

+0

Я бы утвердил, что hk2 - это универсальная инжекционная рама ;-) – jwells131313

+0

@ jwells131313 вы абсолютно правы :) – pandaadb

ответ

1

Как отметил jwells - HK2 является основой для инъекций :)

Я провел некоторое время, глядя на него, - я должен сказать, я считаю, это намного сложнее, чем, скажем, Guice или весной. Возможно, это связано с тем, что я использую Dropwizard, и это затрудняет доступ к локаторам службы.

Однако, вот как вы можете это сделать.

Во-первых, вам нужно будет получить ссылку на ваш ServiceLocator. Это должен быть тот же ServiceLocator, что и джерси. Вы можете получить доступ к нему, например, как:

How to get HK2 ServiceLocator in Jersey 2.12?

В моем примере кода я буду использовать слушатель событий, который из-за моей Dropwizard установки.

Теперь у вас есть 2 варианта: зарегистрируйте свою команду с помощью своего локатора сервисов и создайте дескриптор рамки инъекции или передайте ServiceLocator вашей команде, чтобы использовать его.

Я написал быстрый пример использования Dropwizard и трикотаж:

public class ViewApplication extends io.dropwizard.Application<Configuration> { 

    @Override 
    public void run(Configuration configuration, Environment environment) throws Exception { 

     environment.jersey().register(new ApplicationEventListener() { 
      @Override 
      public void onEvent(ApplicationEvent event) { 
       if (event.getType() == ApplicationEvent.Type.INITIALIZATION_FINISHED) { 
        ServiceLocator serviceLocator = ((ServletContainer) environment.getJerseyServletContainer()) 
          .getApplicationHandler().getServiceLocator(); 

        ServiceLocatorUtilities.bind(serviceLocator, new AbstractBinder() { 

         @Override 
         protected void configure() { 
          bind(new Repository("test")).to(Repository.class); 
          bind(MyCommandInjected.class).to(MyCommandInjected.class); 
         } 
        }); 

        MyCommandInjected service = serviceLocator.getService(MyCommandInjected.class); 
        MyCommandManual tmp = new MyCommandManual(serviceLocator); 
       } 
      } 
      @Override 
      public RequestEventListener onRequest(RequestEvent requestEvent) { 
       return null; 
      } 
     }); 


    } 

    @Override 
    public void initialize(Bootstrap<Configuration> bootstrap) { 
     super.initialize(bootstrap); 
    } 

    public static void main(String[] args) throws Exception { 
     new ViewApplication().run("server", "/home/artur/dev/repo/sandbox/src/main/resources/config/test.yaml"); 
    } 

    @Path("test") 
    @Produces(MediaType.APPLICATION_JSON) 
    public static class HelloResource { 

     @GET 
     @Path("asd") 
     public String test(String x) { 
      return "Hello"; 
     } 

    } 

    public static class Repository { 

     @Inject 
     public Repository(String something) { 
     } 
    } 

    public static class MyCommandInjected { 

     @Inject 
     public MyCommandInjected(final Repository repo) { 
      System.out.println("Repo injected " + repo); 
     } 
    } 

    public static class MyCommandManual { 

     public MyCommandManual(final ServiceLocator sl) { 
      Repository service = sl.getService(Repository.class); 
      System.out.println("Repo found: " + service); 
     } 
    } 

} 

В методе Run, я получить доступ к моей ServiceLocator. Я связываю свои классы там (так что есть пример того, как это сделать). Вы также можете также зарегистрировать Binders с трикотажем напрямую - они будут использовать правильный ServiceLocator.

2 классы MyCommandInjected и MyCommandManual являются примерами того, как вы можете создать эту команду.

Соответствующая строка для вас, вероятно:

Repository service = sl.getService(Repository.class); 

Это просит локатор сервиса для нового экземпляра Repository.

Теперь это просто быстрый пример. Я гораздо больше увлекаюсь графическим мостом, чем напрямую с помощью HK2. Я нахожу его намного проще в использовании и гораздо яснее. Используя guice-jersey-bridge, вы можете делать все через guice, и он автоматически сделает все правильно.

Надежда, которая приносит некоторую внутреннюю,

Артур

+0

Очевидно, вы можете врезаться в ServiceLocator. – Migaoli

+0

@Migaoli имеет смысл, так как ресурс создается одним и тем же локатором сервисов. – pandaadb

0

Вы можете использовать inject метод ServiceLocator для того, чтобы придать уже созданные объекты , ServiceLocator является основным реестром HK2 и должен быть доступен на вашем ресурсе.

Смежные вопросы