是否可以告诉Guice在定时给定类型的对象后调用某个方法(即init())?
我在EJB 3中寻找类似于@PostConstruct注释的功能。
实际上,这是可能的。
你需要定义一个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()
方法中。在实例化对象后它将自动运行。
我喜欢http://code.google.com/p/mycila/wiki/MycilaGuice。除了http://code.google.com/p/guiceyfruit之外,它还支持Guice 3。
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);
}
});
}
}
GWizard包含一个模块(gwizard-services
),以Guice友好的格式提供Guava服务。 Guava服务为您提供并行线程的生命周期管理。
如果您想在构造实例后调用方法,则意味着后构造方法调用实际上是实例创建的一个步骤。在这种情况下,我会建议抽象工厂设计模式来解决这个问题。代码可能看起来像这样:
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)
如果你需要使用其他对象初始化一个对象,并且在两个对象准备好之后(如果你需要将另一个对象注册,并且它们也相互依赖),你可以像这样轻松地做到这一点:
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);
}
}