Guice子模块阻止继承绑定

时间:2013-04-26 06:48:11

标签: java inheritance module override guice

我想在不引入注释或使用字符串键名的情况下完成以下操作,是否可以使用Guice?此外,为MyService及其ExecutorService绑定引入第三个私有模块并不理想,因为我希望ExecutorService成为整个应用程序的单例,不仅仅在{{1}中注入但是,可能还有其他类,比如说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); } } 都反映了各自的RedModule, RedService and RedServiceImpl类。

最后Blue*,它使用MyServiceRed以及它自己的Blue Services

ExecutorService

1 个答案:

答案 0 :(得分:10)

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

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

私人模块可以帮助您完成大部分工作,请参阅my experimentation

但是...

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

public class MyAppModule extends PrivateModule {
  bind(AwesomeService.class).to(AwesomeServiceImpl.class);
  expose(AwesomeService.class);
}

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

class AwesomeServiceImpl implements AwesomeService {
  @Inject
  AwesomeServiceImpl(BlueService blue, RedService red, ExecutorService executor) { ... }
}

正是如此,一些正直的互联网居民已经创建了一个带有Guice模块的独立jar,它提供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);
}

我的ExecutorService还需要一个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);
}

啊,但该死的,显然我的好网友决定不仅揭露我RedService需要的BlueServiceAwesomeService绑定,还要公开我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);
}

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

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

啊,但该死的,我的ExecutorService绑定是由我的私有包装器模块继承的,并且与RedModuleBlueModule中定义的内部绑定冲突。我想我可以在我的ExecutorService构造函数中注释或命名我的AwesomeService,但是如果我希望ExecutorService成为我的应用程序共享的单例,那么20,30或40不同服务。我将不得不用这个注释污染我的所有ExecutorService注射。

或者我想我可以做一些诡计,错开绑定并隐藏ExecutorService,这样它就不会与ExecutorServiceRedModule创建的BlueModule冲突,但这似乎错了:

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

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

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

现在,ExecutorServiceBlueModule中绑定和展示的RedModule不会污染我的AwesomeService's ExecutorService,但我仍然可以获得我非常想要那些多汁的BlueServiceRedService课程。

希望将来某个时候可以节省其他人的时间!