Guice在依赖层次结构中更深入地协助注入 [英] Guice assisted injection deeper down the dependency hierarchy
问题描述
我想进行一系列处理元素并通过Guice将它们连接在一起。我们假设以下路径:
I want to conduct a chain of processing elements and wire them together via Guice. Let's assume the following path:
-
接口A
由类AImpl
需要一些输入 -
接口B
由类实现BIPL
需要A
-
接口C
由class CImpl
需要B
-
界面D
由类DImpl实现
需要C
interface A
implemented byclass AImpl
needs some inputinterface B
implemented byclass BImpl
needsA
interface C
implemented byclass CImpl
needsB
interface D
implemented byclass DImpl
needsC
A的依赖关系只能在运行时解决,而不能在配置时解析。通常的做法是在这种情况下使用辅助注入创建一个工厂,将缺少的实例作为参数,如下所示:
The dependency of A can only be resolved at runtime and not at configuration time. The usual approach would be to use Assisted Injection in this case to create a factory, that takes the missing instances as parameters, just like this:
public interface AFactory {
public A createA(String input);
}
但我真正想要的是这样的:
But what I actually want is something like this:
public interface DFactory {
public D createD(String inputForA);
}
我不想手动传递 AImpl
整个层次结构中的特定依赖项。
是否可以通过Guice实现这一目标?如果没有,那么在保留注射效益的同时优雅地避开这个问题的最佳方法是什么?
I don't want to manually pass AImpl
-specific dependencies through the whole hierarchy.
Is it possible to achieve this with Guice? If not, what's the best way to circumvent this problem elegantly while still retaining benefits of injection?
推荐答案
作弊方式: 在静态变量或单件 ThreadLocal
中粘贴输入
。在管道启动之前设置它并在它结束后清除它。通过DI绑定其他所有内容。
Cheating way: Stick input
in a static variable or singleton ThreadLocal
. Set it before your pipeline starts and clear it after it ends. Bind everything else through DI.
花哨的方式:在 A
中,请参阅 @PipelineInput String inputString
但不要在主进样器中绑定它。否则,像往常一样绑定依赖项,包括在其他管道相关类中引用 @PipelineInput
。当你需要 D
时,从你的 DFactory
的实现中获取它,我正在调用 PipelineRunner
。
Fancy way: In A
, refer to a @PipelineInput String inputString
but don't bind it in your main injector. Otherwise, bind dependencies as you normally would, including referring to @PipelineInput
in other pipeline-related classes. When you do need a D
, get it from your implementation of a DFactory
, which I'm calling 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 $由于缺少
@PipelineInput字符串
,c $ c>将在 PipelineRunner
之外失败 - 你会得到一个 CreationException
当您创建具有那些未满足的依赖项的注入器时,如您所发现的那样 - 但是这些基于管道的依赖项应该很容易分离到您安装到子注入器中的模块中。
Naturally, binding attempts for A
, B
, C
, and D
will fail outside of PipelineRunner
for lack of a @PipelineInput String
--you'll get a CreationException
when you create the injector with those unsatisfied dependencies, as you discovered--but those pipeline-based dependencies should be easy to separate into a Module that you install into the child injector.
如果这感觉太过苛刻,请记住PrivateModules也是使用父注入器实现,并且依赖注入的整个点是产生依赖,如 inputForA
以分离的方式可用于整个对象图。
If this feels too hacky, remember that PrivateModules are also "implemented using parent injectors", and that the whole point of dependency injection is to make a dependency like inputForA
available to the whole object graph in a decoupled way.
这篇关于Guice在依赖层次结构中更深入地协助注入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!