Guice call init-methode na het instantineren van een object

Is het mogelijk om Guice te vertellen om een ​​methode (bijv. init()) aan te roepen na
instantineren van een object van een bepaald type?

Ik zoek naar functionaliteit vergelijkbaar met @PostConstruct-annotatie in EJB 3 (en Spring).


Antwoord 1, autoriteit 100%

Je kunt gewoon de annotatie @Injecttoevoegen aan je init()-methode. Het wordt automatisch uitgevoerd nadat het object is geïnstantieerd.


Antwoord 2, autoriteit 72%

Eigenlijk is het mogelijk.

Je moet een TypeListenerdefiniëren om de functionaliteit op gang te krijgen. Iets in de trant van het volgende in uw moduledefinitie:

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

Antwoord 3, autoriteit 14%

guiceyfruitdoet wat u zoekt voor methoden die zijn geannoteerd met @PostConstructof het implementeren van Spring’s InitializingBean. Het is ook mogelijk om je eigen luisteraars te schrijven om dit te doen. Hier is een voorbeeld dat een openbare init()-methode aanroept nadat objecten zijn gemaakt.

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

Antwoord 4, autoriteit 11%

Ik hou van http://code.google.com/p/mycila/wiki/MycilaGuice. Dit ondersteunt Guice 3, behalve http://code.google.com/p/guiceyfruit.


Antwoord 5, autoriteit 3%

Als je een methode wilt aanroepen na de constructie van een instantie, betekent dit dat de post-construct methodeaanroep in feite een stap is van het maken van de instantie. In dit geval zou ik een abstract fabrieksontwerppatroon aanbevelen om dit probleem op te lossen.
De code kan er ongeveer zo uitzien:


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)

Antwoord 6, autoriteit 2%

GWizard bevat een module (gwizard-services) die Guava-services levert in een Guice-vriendelijk formaat. Guava-services bieden u levenscyclusbeheer in parallelle threads.

https://github.com/stickfigure/gwizard


Antwoord 7

In het geval dat u een object moet initialiseren met andere objecten en nadat beide gereed zijn (wat het geval is als u de een met de ander moet registreren en ze ook van elkaar afhankelijk zijn), kunt u dit eenvoudig als volgt doen:

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

Antwoord 8

Op basis van Geoff’s antwoordkun je de @PostConstructmethode “oproepbaar maken”:

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

U kunt ook meerdere @PostConstruct-methoden hebben, maar u weet niet in welke volgorde ze worden aangeroepen:

@PostConstruct
private void init() {
    dataManager.printData();
}
@PostConstruct
private void init2() {
    System.out.println("Other init method");
}

Other episodes