如何处理多个guice私有模块的循环依赖?

时间:2013-01-10 20:48:02

标签: java guice circular-dependency

我目前正在编写一些框架代码,为我们平台中的服务提供蓝图,以便服务实现者可以专注于特定于服务的逻辑而不是样板集成代码。依赖注入是通过guice完成的。

蓝图有两种类型的逻辑组件;

  1. 1且只有1个集成了该服务与外部世界的集成组件(消息传递中间件等)
  2. 1-n业务逻辑组件
  3. 每个逻辑组件都依赖于集成组件。

    集成组件依赖于所有逻辑组件。

    由于这是框架代码,因此框架不了解任何具体细节,因此无法静态声明依赖关系并形成依赖关系图。我想避免让服务实现者这样做,因为这意味着他们正在重复自己(只是声明他们有n个业务逻辑模块意味着他们有这种循环依赖)。

    我的问题是,如果没有使服务实现者编写样板代码,我可以采取哪些方法

    请注意,此处不提供多绑定,因为出于此问题范围之外的各种原因,每个业务逻辑组件必须是PrivateModule。

    一个人为的例子来说明

    1. 业务逻辑= ModuleA,ModuleB,ModuleC
    2. 依赖性由integration = Wrapper提供
    3. 集成对业务逻辑的依赖性由每个逻辑模块向Wrapper添加内容建模
    4. 可以通过更改

      使此示例正常工作
      @Provides @Exposed @Named("result")
      public String go(Container in) {
          return in.format();
      }
      

      @Provides @Exposed @Named("result")
      public String go(@Named("a") Container in, @Named("b") Container in2, @Named("c") Container in3) {
          return in.format();
      }
      

      即。通过实际创建循环依赖。

      import com.google.inject.Exposed;
      import com.google.inject.Guice;
      import com.google.inject.Injector;
      import com.google.inject.Key;
      import com.google.inject.PrivateModule;
      import com.google.inject.Provides;
      import com.google.inject.Singleton;
      import com.google.inject.name.Named;
      import com.google.inject.name.Names;
      
      import java.util.ArrayList;
      import java.util.List;
      
      public class GuiceCircularDependencyTest {
      
          public static void main(String[] args) {
              Injector in = Guice.createInjector(new Owner());
              String result = in.getInstance(Key.get(String.class, Names.named("result")));
              System.out.println("Result is: " + result);
          }
      
          public static class Owner extends PrivateModule {
              @Override
              protected void configure() {
                  bind(Container.class).in(Singleton.class);
                  install(new Integration());
                  install(new ModuleA());
                  install(new ModuleB());
                  install(new ModuleC());
                  expose(String.class).annotatedWith(Names.named("result"));
              }
          }
      
          public static class ModuleA extends PrivateModule {
      
              @Override
              protected void configure() {
      
              }
      
              @Provides @Exposed @Named("a")
              public Container go(Container in, Wrapper prefix) {
                  in.add(prefix + "A");
                  return in;
              }
          }
      
          public static class ModuleB extends PrivateModule {
      
              @Override
              protected void configure() {
      
              }
      
              @Provides @Exposed @Named("b")
              public Container go(Container in, Wrapper prefix) {
                  in.add(prefix + "B");
                  return in;
              }
          }
      
          public static class ModuleC extends PrivateModule {
      
              @Override
              protected void configure() {
      
              }
      
              @Provides @Exposed @Named("c")
              public Container go(Container in, Wrapper prefix) {
                  in.add(prefix + "C");
                  return in;
              }
          }
      
          public static class Integration extends PrivateModule {
              @Override
              protected void configure() {
                  bind(Wrapper.class).toInstance(new Wrapper("Module"));
                  expose(Wrapper.class);
              }
      
              @Provides @Exposed @Named("result")
              public String go(Container in) {
                  return in.format();
              }
          }
      
          public static class Container {
              private List<String> strings = new ArrayList<>();
      
              public void add(String string) {
                  strings.add(string);
              }
      
              public String format() {
                  return strings.toString();
              }
          }
      
          public static class Wrapper {
              private final String prefix;
      
              public Wrapper(String prefix) {
                  this.prefix = prefix;
              }
      
              @Override
              public String toString() {
                  return prefix;
              }
          }
      }
      

1 个答案:

答案 0 :(得分:0)

允许在私有模块之间共享Multibinder的一种解决方法是将PrivateModule包装在只安装AbstractModule的{​​{1}}实现中并绑定公开了PrivateModule

的密钥
Multibinder