69

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

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

4

8 回答 8

65

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

于 2011-05-20T14:01:43.433 回答
46

实际上,这是可能的。

您需要定义 aTypeListener以使功能正常运行。在您的模块定义中类似于以下内容:

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();
            }
        });
    }
});
于 2010-01-19T13:46:42.320 回答
9

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);
      }
    });
  }
}
于 2010-01-19T14:53:03.927 回答
7

我喜欢http://code.google.com/p/mycila/wiki/MycilaGuice。这支持 Guice 3,而不是http://code.google.com/p/guiceyfruit

于 2011-04-15T10:13:10.407 回答
2

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


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)
于 2019-05-14T09:47:53.440 回答
1

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

https://github.com/stickfigure/gwizard

于 2015-01-22T02:22:51.723 回答
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);
  }

}
于 2019-04-03T10:20:28.863 回答
-1

根据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");
}
于 2020-03-07T12:43:55.380 回答