我想进行一系列处理元素并通过Guice将它们连接在一起。让我们假设以下路径:
interface A
实施的class AImpl
需要一些输入interface B
class BImpl
实施的A
由interface C
class CImpl
B
由interface D
class DImpl
C
A的依赖关系只能在运行时解决,而不能在配置时解决。通常的做法是在这种情况下使用辅助注入来创建一个工厂,它将缺少的实例作为参数,就像这样:
public interface AFactory {
public A createA(String input);
}
但我真正想要的是这样的事情:
public interface DFactory {
public D createD(String inputForA);
}
我不想在整个层次结构中手动传递AImpl
特定的依赖项。
是否可以通过Guice实现这一目标?如果没有,那么在保留注射效益的同时优雅地避免这个问题的最佳方法是什么?
答案 0 :(得分:7)
作弊方式:将input
粘贴到静态变量或单身ThreadLocal
中。在管道启动之前设置它并在它结束后清除它。通过DI绑定其他所有内容。
花哨的方式:在A
中,请参阅@PipelineInput String inputString
,但不要将其绑定在主进样器中。否则,像往常一样绑定依赖关系,包括引用其他管道相关类中的@PipelineInput
。如果您确实需要D
,请从DFactory
的实施中获取,我正在呼叫PipelineRunner
。
public class PipelineRunner {
@Inject Injector injector; // rarely a good idea, but necessary here
public D createD(final String inputForA) {
Module module = new AbstractModule() {
@Override public void configure() {
bindConstant(inputForA).annotatedWith(PipelineInput.class);
}
};
return injector.createChildInjector(new PipelineModule(), module)
.getInstance(D.class);
}
}
当然,由于缺少A
,B
,C
,D
和PipelineRunner
的绑定尝试将在@PipelineInput String
之外失败 - 正如您所发现的那样,当您使用那些不满意的依赖项创建注入器时,您将获得CreationException
- 但是这些基于管道的依赖项应该很容易分离到您安装到子注入器中的模块中。 / p>
如果这感觉太乱,请记住,PrivateModules也是“implemented using parent injectors”,并且依赖注入的整个要点是使得inputForA
之类的依赖关系可以在解耦的整个对象图中使用方式。
答案 1 :(得分:1)
我看到三个选项。它们取决于您更改input
的{{1}}的频率。
1)将A
绑定为模块中的常量。如果您在创建input
之前知道该值并且从不想更改该值,则此方法有效。见bindConstant
2)使用私有子模块,该子模块绑定Injector
或该模块内A
的值。基本上,您可以有两个或三个具有不同值的实例图。请参阅newPrivateBinder。
3)使用input
ala Scope
,RequestScope
,...这样您可以经常更改输入,但您必须进入/离开在某些时候要确定的范围。有关示例,请参阅Custom Scopes。