Guice在依赖层次结构中更深入地协助注入 [英] Guice assisted injection deeper down the dependency hierarchy

查看:125
本文介绍了Guice在依赖层次结构中更深入地协助注入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想进行一系列处理元素并通过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 by class AImpl needs some input
  • interface B implemented by class BImpl needs A
  • interface C implemented by class CImpl needs B
  • interface D implemented by class DImpl needs C

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆