在即时化对象后,Guice调用init方法

问题描述 投票:58回答:7

是否可以告诉Guice在定时给定类型的对象后调用某个方法(即init())?

我在EJB 3中寻找类似于@PostConstruct注释的功能。

guice init postconstruct
7个回答
34
投票

实际上,这是可能的。

你需要定义一个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();
            }
        });
    }
});

57
投票

您可以将@Inject注释添加到init()方法中。在实例化对象后它将自动运行。


7
投票

7
投票

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

1
投票

GWizard包含一个模块(gwizard-services),以Guice友好的格式提供Guava服务。 Guava服务为您提供并行线程的生命周期管理。

https://github.com/stickfigure/gwizard


1
投票

如果您想在构造实例后调用方法,则意味着后构造方法调用实际上是实例创建的一个步骤。在这种情况下,我会建议抽象工厂设计模式来解决这个问题。代码可能看起来像这样:


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)

0
投票

如果你需要使用其他对象初始化一个对象,并且在两个对象准备好之后(如果你需要将另一个对象注册,并且它们也相互依赖),你可以像这样轻松地做到这一点:

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

}
© www.soinside.com 2019 - 2024. All rights reserved.