web-dev-qa-db-fra.com

Guice call init method after instinating an object

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.

61
mgamer

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();
            }
        });
    }
});
36
gpampara

Vous pouvez simplement ajouter l'annotation @Inject À votre méthode init(). Il s'exécutera automatiquement après l'instanciation de l'objet.

58
Simon Nickerson

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);
      }
    });
  }
}
7
Geoff Reedy
7

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)
1
Russell Bie

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.

https://github.com/stickfigure/gwizard

1
stickfigure

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);
  }

}
0
kboom