有没有可能让Guice在实例化给定类型的对象后调用某个方法(如init())?
我正在寻找类似于EJB 3(和Spring)中的@PostConstruct注释的功能。
有没有可能让Guice在实例化给定类型的对象后调用某个方法(如init())?
我正在寻找类似于EJB 3(和Spring)中的@PostConstruct注释的功能。
您只需将@Inject
注解添加到init()
方法即可。对象实例化后,它会自动运行。
@Inject
注释。 - Mansoor Siddiqui实际上,这是可能的。
你需要定义一个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();
}
});
}
});
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。
如果您想在实例构建后调用方法,这意味着后置构造方法调用实际上是实例创建的一步。在这种情况下,我建议使用抽象工厂设计模式来解决这个问题。代码可能类似于:
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)
GWizard包含一个模块(gwizard-services
),该模块以Guice友好的格式提供Guava服务。 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);
}
}
根据Geoff的回答,您可以“调用”@PostConstruct
方法:
public class GuiceExample {
@Inject
private IDataManager dataManager;
public GuiceExample() {
System.out.println("Constructor");
}
@PostConstruct
private void init() {
dataManager.printData();
}
public static void main(String[] args) {
Injector injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bind(IDataManager.class).to(DataManager.class);
bindListener(HasPostConstructAnnotationMatcher.INSTANCE, new TypeListener() {
@Override
public <I> void hear(TypeLiteral<I> type, TypeEncounter<I> encounter) {
encounter.register(PostConstructAnnotationInvoker.INSTANCE);
}
});
}
});
GuiceExample example = injector.getInstance(GuiceExample.class);
}
private static class HasPostConstructAnnotationMatcher extends AbstractMatcher<TypeLiteral<?>> {
private static final HasPostConstructAnnotationMatcher INSTANCE = new HasPostConstructAnnotationMatcher();
@Override
public boolean matches(TypeLiteral<?> t) {
return Arrays.stream(t.getRawType().getDeclaredMethods()).anyMatch(GuiceExample::hasPostConstructAnnotation);
}
}
private static boolean hasPostConstructAnnotation(Method method) {
Annotation[] declaredAnnotations = method.getAnnotations();
return Arrays.stream(declaredAnnotations).anyMatch(a -> a.annotationType().equals(PostConstruct.class));
}
private static class PostConstructAnnotationInvoker implements InjectionListener<Object> {
private static final PostConstructAnnotationInvoker INSTANCE = new PostConstructAnnotationInvoker();
@Override
public void afterInjection(Object injectee) {
//@formatter:off
Arrays.stream(injectee.getClass().getDeclaredMethods())
.filter(GuiceExample::hasPostConstructAnnotation)
.forEach(m -> {
try {
m.setAccessible(true);
m.invoke(injectee);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
e.printStackTrace();
}
});
//@formatter:on
}
}
public static interface IDataManager {
void printData();
}
public static class DataManager implements IDataManager {
@Override
public void printData() {
System.out.println("I print data.");
}
}
}
此外,您可以拥有多个@PostConstruct
方法,但您不会知道它们将以何种顺序被调用:
@PostConstruct
private void init() {
dataManager.printData();
}
@PostConstruct
private void init2() {
System.out.println("Other init method");
}