Guice子模块阻止继承绑定

Mat*_*son 5 java inheritance overriding module guice

我想在不引入注释或使用字符串键名的情况下完成以下操作,是否可以使用Guice?此外,引入第三个私有模块MyService及其ExecutorService绑定并不理想,因为我希望ExecutorService成为整个应用程序的单例,不仅可以注入,还可以注入MyService其他类,MyOtherService例如.

public class Main {
  public static void main(String[] args) {
    final Injector injector = Guice.createInjector(new MyAppModule());
    final MyService service = injector.getInstance(MyService.class);
    service.printInternals();
    // Ideally this would print something like:
    // My Executor: ExecutorImplClass@1
    // Red Executor: ExecutorImplClass@2
    // Blue Executor: ExecutorImplClass@3
  }
}

public class MyAppModule extends PrivateModule {
  @Override
  protected void configure() {
    install(new RedModule());
    install(new BlueModule());
    bind(ExecutorService.class).toInstance(Executors.newSingleThreadExecutor());
    bind(MyService.class).to(MyServiceImpl.class);
    expose(MyService.class);
  }
}

public class BlueModule extends PrivateModule {
  @Override
  protected void configure() {
    bind(ExecutorService.class).toInstance(Executors.newSingleThreadExecutor());
    bind(BlueService.class).to(BlueServiceImpl.class);
    expose(BlueService.class);
  }
}

public interface BlueService {
  void printInternals();
}

class BlueServiceImpl implements BlueService {
  private final ExecutorService executor;

  @Inject
  BlueServiceImpl(final ExecutorService executor) {
    this.executor = executor;
  }

  @Override
  public void printInternals() {
    System.out.println("Blue Executor: " + executor);
  }
}
Run Code Online (Sandbox Code Playgroud)

RedModule, RedService and RedServiceImpl所有镜像它们各自的Blue*类.

最后MyService,它使用RedBlue Services它自己的ExecutorService:

class MyServiceImpl implements MyService {
  private final ExecutorService executor;
  private final RedService red;
  private final BlueService blue;

  @Inject
  MyServiceImpl(final ExecutorService executor, final RedService red, final BlueService blue) {
    this.executor = executor;
    this.red = red;
    this.blue = blue;
  }

  @Override
  public void printInternals() {
    System.out.println("My Executor: " + executor);
    red.printInternals();
    blue.printInternals();
  }
}
Run Code Online (Sandbox Code Playgroud)

Mat*_*son 10

TL; DR:将模块BlueRed模块隔离到它们自己的注入器,并在App's模块中创建提供程序,这些提供程序调用getInstance()注入器的方法来检索应用程序所需的服务.

现在我是如何找到解决方案的:

私有模块可以帮助你完成大部分工作,看看我的实验.

但...

假设我正在开发一个使用服务来做一些非常棒的应用程序的应用程序.

public class MyAppModule extends PrivateModule {
  bind(AwesomeService.class).to(AwesomeServiceImpl.class);
  expose(AwesomeService.class);
}
Run Code Online (Sandbox Code Playgroud)

现在我的特定实现AwesomeService需要一些令人敬畏的事情:

class AwesomeServiceImpl implements AwesomeService {
  @Inject
  AwesomeServiceImpl(BlueService blue, RedService red, ExecutorService executor) { ... }
}
Run Code Online (Sandbox Code Playgroud)

事实上,一些正直的互联网居民已经创建了一个独立的jar,其中包含Guice模块RedBlue服务.所以我将jar添加到我的类路径并修改,MyAppModule以便我AwesomeService可以使用第三方RedBlue服务:

public class MyAppModule extends PrivateModule {
  install(new RedModule());
  install(new BlueModule());
  bind(AwesomeService.class).to(AwesomeServiceImpl.class);
  expose(AwesomeService.class);
}
Run Code Online (Sandbox Code Playgroud)

我还需要一个ExecutorServicefor my AwesomeService,所以我现在继续绑定到一个显式实例:

public class MyAppModule extends PrivateModule {
  install(new RedModule());
  install(new BlueModule());
  bind(ExecutorService.class).toInstance(Executors.newSingleThreadExecutor());
  bind(AwesomeService.class).to(AwesomeServiceImpl.class);
  expose(AwesomeService.class);
}
Run Code Online (Sandbox Code Playgroud)

啊,但该死的,显然我的好网友决定不仅揭露我需要的RedServiceBlueService绑定AwesomeService,而且还是ExecutorService我不想要的:

public final class BlueModule extends PrivateModule {
  bind(ExecutorService.class).toInstance(Executors.newCachedThreadPool());
  bind(BlueService.class).to(BlueServiceImpl.class);

  expose(ExecutorService.class);
  expose(BlueService.class);
}

public final class RedModule extends PrivateModule {
  bind(ExecutorService.class).toInstance(Executors.newCachedThreadPool());
  bind(RedService.class).to(RedServiceImpl.class);

  expose(ExecutorService.class);
  expose(RedService.class);
}
Run Code Online (Sandbox Code Playgroud)

没问题,我只是将他的模块包装在一个私有模块中,只公开我关心的服务:

public class MyAppModule extends PrivateModule {
  install(new PrivateModule() {
    install(new RedModule());
    expose(RedService.class);
  });
  install(new PrivateModule() { 
    install(new BlueModule());
    expose(BlueService.class);
  });
  bind(ExecutorService.class).toInstance(Executors.newSingleThreadExecutor());
  bind(AwesomeService.class).to(AwesomeServiceImpl.class);
  expose(AwesomeService.class);
}
Run Code Online (Sandbox Code Playgroud)

啊,但该死再次,我的ExecutorService结合是我的私人包装模块继承,并与在定义的内部冲突的绑定RedModuleBlueModule.我想我可以ExecutorService在我的AwesomeService构造函数中注释或命名我,但是如果我希望它ExecutorService是一个单独在我的应用程序中共享的单例,通过20,30或40种不同的服务.我将不得不ExecutorService用这个注释污染我的所有注射.

或者我想我可以做一些诡计,错开绑定并隐藏ExecutorService它,所以它不与ExecutorService那个RedModuleBlueModule创造冲突,但这似乎是错误的:

public class MyAppModule extends PrivateModule {
  install(new PrivateModule() {
    install(new RedModule());
    expose(RedService.class);
  });
  install(new PrivateModule() { 
    install(new BlueModule());
    expose(BlueService.class);
  });

  final Module myAppExecutorService = new PrivateModule() {
    bind(ExecutorService.class).toInstance(Executors.newSingleThreadExecutor());  
    expose(ExecutorService.class);
  };
  install(new PrivateModule() {
    install(myAppExecutorService);
    bind(AwesomeService.class).to(AwesomeServiceImpl.class);
    expose(AwesomeService.class);
  });  
  expose(AwesomeService.class);
}
Run Code Online (Sandbox Code Playgroud)

必须有一个更好的方法......并且有...注射器!

public class MyAppModule extends PrivateModule {
  private static final Injector blueInjector = Guice.createInjector(new BlueModule());
  private static final Injector redInjector = Guice.createInjector(new RedModule());

  @Override
  protected void configure()
  {
    bind(ExecutorService.class).toInstance(Executors.newSingleThreadExecutor());
    bind(MyService.class).to(MyServiceImpl.class);
    bind(MyOtherService.class).to(MyOtherServiceImpl.class);
    expose(MyService.class);
    expose(MyOtherService.class);
  }

  @Provides
  RedService getRedService()
  {
    return redInjector.getInstance(RedService.class);
  }

  @Provides
  BlueService getBlueService()
  {
    return blueInjector.getInstance(BlueService.class);
  }
}
Run Code Online (Sandbox Code Playgroud)

现在,ExecutorService绑定和两个外露BlueModuleRedModule不会污染我的AwesomeService's ExecutorService,但我仍然可以得到我的手对那些多汁BlueServiceRedService班级我这么拼命的想.

希望这将在未来的某个时间节省其他人!