Java Guice帮助深入依赖关系层次结构的注入

Java Guice帮助深入依赖关系层次结构的注入,java,guice,Java,Guice,我想引导一系列处理元素,并通过Guice将它们连接在一起。让我们假设以下路径: 类AImpl实现的接口A需要一些输入 接口B由类BImpl实现需要A 接口C由类CImpl实现需要B 接口D由类DImpl实现需要C 的依赖关系只能在运行时解析,而不能在配置时解析。通常的方法是在这种情况下使用辅助注入来创建工厂,该工厂将缺少的实例作为参数,如下所示: public interface AFactory { public A createA(String input); } public

我想引导一系列处理元素,并通过Guice将它们连接在一起。让我们假设以下路径:

  • 类AImpl实现的接口A
    需要一些输入
  • 接口B
    类BImpl实现
    需要
    A
  • 接口C
    类CImpl实现
    需要
    B
  • 接口D
    类DImpl实现
    需要
    C
的依赖关系只能在运行时解析,而不能在配置时解析。通常的方法是在这种情况下使用辅助注入来创建工厂,该工厂将缺少的实例作为参数,如下所示:

public interface AFactory {
    public A createA(String input);
}
public interface DFactory {
    public D createD(String inputForA);
}
但我真正想要的是这样的:

public interface AFactory {
    public A createA(String input);
}
public interface DFactory {
    public D createD(String inputForA);
}
我不想在整个层次结构中手动传递特定于AImpl的依赖项。
使用Guice可以实现这一点吗?如果没有,在保留注射的好处的同时,优雅地规避这个问题的最佳方法是什么?

我有三种选择。它们取决于您为
A
更改
输入的频率

1) 将
输入绑定为模块中的常量。仅当您在创建
喷油器之前知道该值并且从不想更改该值时,此操作才有效。看

2) 使用一个私有子模块,该子模块将
a
input
的值绑定到该模块中。基本上,可以有两个或三个具有不同值的实例图。看


3) 使用
Scope
ala
RequestScope
SessionScope
。。。通过这种方式,您可以经常更改输入,但您必须在某个待定义点进入/离开范围。请参见示例。

欺骗方式:
输入
粘贴到静态变量中,或使用单例
线程本地
。在管道开始之前设置它,并在管道结束后清除它。通过DI绑定其他所有内容

奇特的方式:
A
中,请参考
@PipelineInput String inputString
,但不要将其绑定到主注入器中。否则,像通常一样绑定依赖项,包括在其他管道相关类中引用
@PipelineInput
。当您确实需要
D
时,请从我调用的
PipelineRunner
DFactory实现中获取它

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
,正如您所发现的——但是这些基于管道的依赖关系应该很容易分离到一个模块中,然后安装到子注入器中


如果这感觉太粗糙,请记住PrivateModules也是“”,依赖项注入的全部目的是使类似于
inputForA
的依赖项以解耦的方式可用于整个对象图。

1)为时已晚,2)只是1)的特例。我还考虑了作用域,但这是一个如此小的问题的样板,为了美观起见,我宁愿完全忽略DI:-/我必须回忆起我的批准,因为这样:“a、B、C和d的注入尝试将在PipelineRunner之外失败,因为缺少@PipelineInput字符串”这不起作用,因为Guice在配置时验证注入器,并在检测到未满足的绑定时立即失败,这就是为什么您无法创建一个几乎完整的注入器,该注入器将由其子级完成。私有模块通过使用一个特殊的活页夹来克服这个问题;你必须把A,B,C和D绑定到常数附近。不过,这个问题很难解决。答案已更新。好的,所以我必须将所有与管道相关的内容专门绑定到子注入器中,而父注入器只知道工厂(“PipelineRunner”)。没错。当然,子注入器类可以引用父注入器中绑定的内容。