Можно ли сказать Guice вызвать какой-то метод (т.е. init()) после инициализация объекта данного типа?
Я ищу функциональность, подобную аннотации @PostConstruct в EJB 3.
Можно ли сказать Guice вызвать какой-то метод (т.е. init()) после инициализация объекта данного типа?
Я ищу функциональность, подобную аннотации @PostConstruct в EJB 3.
На самом деле, это возможно.
Вам нужно определить 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();
}
});
}
});
Вы можете просто добавить аннотацию @Inject
к вашему методу init()
. Он будет запускаться автоматически после создания объекта.
guiceyfruit делает то, что вам нужно для методов, аннотированных с помощью @PostConstruct
или реализации spring 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);
}
});
}
}
Мне нравится http://code.google.com/p/mycila/wiki/MycilaGuice. Это поддерживает Guice 3, кроме http://code.google.com/p/guiceyfruit.
GWizard включает в себя модуль (gwizard-services
), который предоставляет сервисы Guava в формате, удобном для Guice. Сервисы Guava предоставляют вам управление жизненным циклом в параллельных потоках.
В случае, если вам нужно инициализировать объект, используя другие объекты, и после того, как оба будут готовы (что имеет место, если вам нужно зарегистрировать один объект вместе с другим, и они также зависят друг от друга), вы можете легко сделать это следующим образом:
public final class ApplicationModule extends AbstractModule {
@Override
protected void configure() {
requestStaticInjection(ApplicationModule.class);
}
@Inject
static void injectApplication(
ReslSession reslSession,
Set<Saga> sagas,
Set<Reaction> reactions
) {
sagas.forEach(reslSession::registerSaga);
reactions.forEach(reslSession::registerReaction);
}
}
Если вы хотите вызвать метод после создания экземпляра, это означает, что вызов метода после конструирования фактически является этапом создания экземпляра. В этом случае я бы порекомендовал абстрактный шаблон фабричного дизайна для решения этой проблемы. Код может выглядеть примерно так:
class A {
public A(Dependency1 d1, Dependency2 d2) {...}
public postConstruct(RuntimeDependency dr) {...}
}
interface AFactory {
A getInstance(RuntimeDependency dr);
}
class AFactoryImpl implements AFactory {
@Inject
public AFactoryImpl(Dependency1 d1, Dependency2 d2) {...}
A getInstance(RuntimeDependency dr) {
A a = new A(d1, d2);
a. postConstruct(dr);
return a;
}
}
// in guice module
bind(AFactory.class).to(AFactoryImpl.class)