Guice assisted injection deeper down the dependency hierarchy

前端 未结 2 1927
南旧
南旧 2020-11-30 12:40

I want to conduct a chain of processing elements and wire them together via Guice. Let\'s assume the following path:

  • interface A implemented by
相关标签:
2条回答
  • 2020-11-30 13:09

    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.

    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);
      }
    }
    

    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.

    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.

    0 讨论(0)
  • 2020-11-30 13:21

    I see three options. They depend on how often you change the input for A .

    1) Bind input as a constant in your module. This works only, if you know that value before you create the Injector and never want to change the value. See bindConstant

    2) Use a private submodule which binds either A or the value for input inside that module. Basically you can have two or three instance graphs with different value. See newPrivateBinder.

    3) Use a Scope ala RequestScope, SessionScope, ... This way you can change the input often but you must enter/leave the scope at some point to be defined. See Custom Scopes for an example.

    0 讨论(0)
提交回复
热议问题