2010-01-19 4 views
53

Можно ли предложить Guice вызвать некоторый метод (т. Е. Init()) после , инициализирующий объект заданного типа?Метод инициализации вызова Guice после создания объекта

Я смотрю на функциональность подобной @PostConstruct аннотации в EJB 3.

+0

, к сожалению, похоже, авторы Guice не намерены добавить @PostConstruct https://github.com/google/guice/issues/62#issuecomment-115452493, который не сильно ограничивает применимость Guice (есть обходные пути, но они довольно многословны). Возможно, вы захотите изучить некоторые другие структуры, такие как Spring или JEE CDI (например, Weld). – arcuri82

ответ

28

На самом деле, это возможно.

Для того, чтобы получить функциональность, вы должны указать TypeListener. Что-то вдоль линий ниже в вашем определении модуля:

bindListener(Matchers.subclassesOf(MyInitClass.class), new TypeListener() { 
    @Override 
    public <I> void hear(final TypeLiteral<I> typeLiteral, TypeEncounter<I> typeEncounter) { 
     typeEncounter.register(new InjectionListener<I>() { 
      @Override 
      public void afterInjection(Object i) { 
       MyInitClass m = (MyInitClass) i; 
       m.init(); 
      } 
     }); 
    } 
}); 
+4

Также можно использовать GuicyFruit, который утверждает, что поддерживает @PostConstruct (см. Http://code.google.com/p/guiceyfruit /), и пока он не отвечает на этот вопрос, я думаю, стоит упомянуть, что если вы (исключительно) используете инъекцию конструктора, вам не нужны такие функциональные возможности, как вы можете выполнить всю инициализацию в конструкторе. – Eelco

+0

спас мой день. @PostConstruct не поддерживается guiceyfruit еще –

+7

Matchers.subclassesOf (MyInitClass.class) фактически приводит к ошибке времени компиляции: «Метод bindListener (> Сличитель, TypeListener) в типе AbstractModule не применяется для аргументов (Matcher , новый TypeListener() {}) " Я думаю, вам придется расширить AbstractMatcher, чтобы заставить ваш код работать – Andrey

6

guiceyfruit делает то, что вы после того, как для методов, аннотированных @PostConstruct или реализации весны InitializingBean. Также можно написать своих собственных слушателей, чтобы это сделать. Вот пример, который вызывает общедоступный метод init() после создания объектов.

import com.google.inject.*; 
import com.google.inject.matcher.*; 
import com.google.inject.spi.*; 

public class MyModule extends AbstractModule { 
    static class HasInitMethod extends AbstractMatcher<TypeLiteral<?>> { 
    public boolean matches(TypeLiteral<?> tpe) { 
     try { 
     return tpe.getRawType().getMethod("init") != null; 
     } catch (Exception e) { 
     return false; 
     } 
    } 

    public static final HasInitMethod INSTANCE = new HasInitMethod(); 
    } 

    static class InitInvoker implements InjectionListener { 
    public void afterInjection(Object injectee) { 
     try { 
     injectee.getClass().getMethod("init").invoke(injectee); 
     } catch (Exception e) { 
     /* do something to handle errors here */ 
     } 
    } 
    public static final InitInvoker INSTANCE = new InitInvoker(); 
    } 

    public void configure() { 
    bindListener(HasInitMethod.INSTANCE, new TypeListener() { 
     public <I> void hear(TypeLiteral<I> type, TypeEncounter<I> encounter) { 
     encounter.register(InitInvoker.INSTANCE); 
     } 
    }); 
    } 
} 
+0

Спасибо за хороший пример, просто интересно, возвращает ли getMethod ("") значение null, потому что, когда он не находит указанный метод, он выдает NoSuchMethodException, и javadoc также не комментирует это. – zeratul021

49

Вы можете просто добавить аннотацию @Inject к вашему методу init(). Он будет запущен автоматически после создания объекта.

+9

Проблема заключается в том, что этот подход не работает, если у вас есть необязательные зависимости, потому что нет способа рассказать о причинах вызова метода init() как последнего метода, насколько я знаю. Имхо им нужна поддержка @PostConstruct. –

+0

Я использую инъекцию конструктора, где мне нужно сделать некоторые элементы инициализации, которые зависят от других зависимостей. –

+1

@OrtwinAngermeier, если я правильно вас понимаю, вы можете поместить аннотацию '@ Inject' на свой конструктор _and_ по методу init. –

1

GWizard включает в себя модуль (gwizard-services), который предоставляет услуги Guava в формате, удобном для Guice. Сервисы Guava предоставляют вам управление жизненным циклом в параллельных потоках.

https://github.com/stickfigure/gwizard

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