在创建模块之前是否可以使用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,但是之前在另一个方法调用中使用它?
答案 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需要执行一些初始化来实现这一点,那么这样做是不合理的,并且模块不是一个不好的地方。