Est-il possible de dire à Guice d'appeler une méthode (c'est-à-dire init ()) après avoir instancié un objet de type donné?
Je recherche des fonctionnalités similaires à l'annotation @PostConstruct dans EJB 3.
En fait, c'est possible.
Vous devez définir un TypeListener
pour lancer la fonctionnalité. Quelque chose dans le sens de ce qui suit dans la définition de votre module:
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();
}
});
}
});
Vous pouvez simplement ajouter l'annotation @Inject
À votre méthode init()
. Il s'exécutera automatiquement après l'instanciation de l'objet.
guiceyfruit fait ce que vous recherchez pour les méthodes annotées avec @PostConstruct
ou implémentant InitializingBean
de Spring. Il est également possible d'écrire vos propres auditeurs pour ce faire. Voici un exemple qui appelle une méthode publique init()
une fois les objets créés.
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);
}
});
}
}
J'aime http://code.google.com/p/mycila/wiki/MycilaGuice . Cela prend en charge Guice 3, autre que http://code.google.com/p/guiceyfruit .
Si vous souhaitez appeler une méthode après la construction d'une instance, cela signifie que l'appel de méthode post-construction est en fait une étape de la création de l'instance. Dans ce cas, je recommanderais un modèle de conception d'usine abstrait pour résoudre ce problème. Le code peut ressembler à quelque chose comme ceci:
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 comprend un module (gwizard-services
) qui fournit des services de goyave dans un format convivial pour Guice. Les services de goyave vous offrent une gestion du cycle de vie dans des threads parallèles.
Si vous devez initialiser un objet à l'aide d'autres objets et que les deux sont prêts (ce qui est le cas si vous devez enregistrer l'un avec l'autre et qu'ils dépendent également les uns des autres), vous pouvez facilement le faire comme ceci:
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);
}
}