Guice:在创建模块之前实例化一个单例

Guice: instantiating a singleton before creating the module

是否可以在创建 Module 之前使用 Guice 实例化一个单例并将其分配给一个引用,然后将该实例传递给 Module 构造函数以在配置期间绑定?

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

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

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

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

编辑,来自下面的评论:

one more thing- didn't want to make the question too long; actually, I also want to perform another operation on the resulting instance of SpecialInterface, but only if it is the instance of DefaultSpecialInterface and I don't think it should be done in the Module. I was thinking if I could just have this bean up and running before, such as in Spring, so I could just pass it to the Module, but also use it in another method call before?

你能把整个 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 执行额外的初始化,您有多种选择:

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

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

  • 如果您的真正目标是将业务逻辑保留在模块之外,您可以通过将其提取到 是 [=35] 的独立 Provider 或 DefaultSpecialInterfaceFactory 中来实现=]对此负责。

请记住,Guice 负责将完全构造的对象提供给您的对象图中,这意味着注入 SpecialInterface 应该得到 SpecialInterface 通用契约的现成可用实现程序。如果 Guice 需要执行一些初始化来实现这一点,让它这样做并不是没有道理的,而且模块是一个不错的地方。