Guice:在创建模块

时间:2015-05-17 18:50:38

标签: java dependency-injection guice

在创建模块之前是否可以使用Guice实例化并将单例分配给引用,并在配置期间将该实例传递给Module构造函数?

这是我的意思的一个例子: 我有一个方法,允许我根据接口的自定义实现创建对象,该接口在构造函数中作为可选项传递(如果用户不能提供自定义实现,我们将使用默认实现),正在通过将接口绑定到Module类中的特定实现来完成。 :

public static MyClass createMyClassObject(Optional<SpecialInterface> customSpecialInterfaceObject) {

    SpecialInterface specialInterfacebject;

    if(customSpecialInterfaceObject.isPresent() {    
        specialInterfaceObject = customSpecialInterfaceObject.get()
    } else {
 /* here I would like to bind it to an instance of the DefaultSpecialInterfaceObject but can't really do something like:
Injector injector = Guice.createInjector(myClassModule);
DefaultSpecialInterface instance = injector.getInstance(DefaultSpecialInterface.class);
as the module is yet to be created */
}
    MyClassModule myClassModule = new MyClassModule(specialInterfaceObject);
    Injector injector = Guice.createInjector(myClassModule);
     return injector.getInstance(MyClass.class);
}

我目前正在使用类而不是实例来解决此问题,例如下面的示例,但我不太喜欢这个解决方案。很高兴看到更好的方法:

private static Class resolveSpecialInterfaceObject(Optional<SpecialInterface> customSpecialInterfaceObject) {
    Class specialInterfaceObjectClass;

    if (customSpecialInterfaceObject.isPresent()) {
        specialInterfaceObjectClass= customSpecialInterfaceObject.get().getClass();
    } else {
        specialInterfaceObjectClass = DefaultSpecialInterface.class;
    }
    return specialInterfaceObjectClass;
}

public abstract class MyClassModule extends AbstractModule {

    private final Class<SpecialInterface> specialInterfaceObjectClass;

    public MyClassModule(Class<SpecialInterface> specialInterfaceObjectClass) {
    this.specialInterfaceObjectClass= specialIntefaceObjectClass;
    }

    @Override
    protected void configure() {
        bind(SpecialInterface.class).to(specialInterfaceObjectClass);
        }
}

根据以下评论进行修改:

  还有一件事 - 不想让问题太长;实际上,我还想对结果的SpecialInterface实例执行另一个操作,但只有当它是DefaultSpecialInterface的实例时,我才认为它应该在模块中完成。我想我是否可以让这个bean在之前运行,比如在Spring中,所以我可以将它传递给Module,但是之前在另一个方法调用中使用它?

1 个答案:

答案 0 :(得分:2)

你能全拿Optional并使用bind(...).toInstance(...)吗?

public static MyClass createMyClassObject(
        Optional<SpecialInterface> customSpecialInterfaceObject) {

    MyClassModule myClassModule = new MyClassModule(customSpecialInterfaceObject);
    Injector injector = Guice.createInjector(myClassModule);
    MyClassFactory instance = injector.getInstance(MyClassFactory.class);
    return instance.createMyClassObject();
}

class MyClassModule extends AbstractModule {
  private final Optional<SpecialInterface> customObject;

  MyClassModule(Optional<SpecialInterface> customObject) {
    this.customObject = customObject;
  }

  @Override public void configure() {
    if (customObject.isPresent()) {
      // Singleton by necessity: Guice doesn't know how to create another one.
      bind(SpecialInterface.class).toInstance(customObject.get());
    } else {
      // Default scoped. Add ".in(Singleton.class)" if necessary.
      bind(SpecialInterface.class).toInstance(DefaultSpecialInterfaceClass.class);
    }
  }
}

如果你想在DefaultSpecialInterface上执行额外的初始化而没有别的,你有很多选择:

  • 如果某种初始化对于所有实现都很重要,并且可能太重而无法放入类构造函数中,请在SpecialInterface上添加initialize方法。使自定义操作成为无操作,并将其实现为DefaultSpecialInterface。

  • 如果初始化对于DefaultSpecialInterface是唯一的,我看不出它为什么不应该在模块中。编写@Provides方法或绑定到正确创建并初始化DefaultSpecialInterface的Provider<SpecialInterface>

  • 如果您的真正目标是将业务逻辑保留在模块之外,则可以通过将其提取到 负责该模块的独立Provider或DefaultSpecialInterfaceFactory来实现。< / p>

请记住,Guice负责将完全构造的对象提供给对象图,这意味着注入SpecialInterface应该可以获得SpecialInterface一般合同的现成实现者。如果Guice需要执行一些初始化来实现这一点,那么这样做是不合理的,并且模块不是一个不好的地方。