有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

在创建模块之前,是否可以用Guice实例化一个引用并将其分配给该引用,并在配置期间将该实例传递给要绑定的模块构造函数

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

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

编辑以下评论:

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?


共 (1) 个答案

  1. # 1 楼答案

    你能把整个Optionalbind(...).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上执行其他初始化操作,则有许多选项:

    • 如果某种初始化对所有实现都很重要,并且可能太重而无法放入类构造函数中,那么在SpecialLinterface上添加initialize方法。将自定义设置为no-op,并为DefaultSpecialLinterface实现它

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

    • 如果您的真正目标是将业务逻辑排除在模块之外,那么可以通过将其提取到一个独立的提供者或DefaultSpecialInterfaceFactory中来实现,该提供者或DefaultSpecialInterfaceFactory负责

    请记住,Guice负责将完全构造的对象输入到对象图中,这意味着注入SpecialInterface应该让SpecialInterface通用契约的实现者随时可用。如果Guice需要执行一些初始化来实现这一点,那么让它这样做并不是不合理的,模块也不是一个不好的地方