5

我想在不引入注释或使用字符串键名的情况下完成以下操作,是否可以使用Guice?此外,引入第三个私有模块 forMyService及其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);
  }
}

RedModule, RedService and RedServiceImpl所有镜像各自的Blue*类。

最后MyService,它使用RedandBlue 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();
  }
}
4

1 回答 1

10

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

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

私有模块可以让你大部分时间到达那里,请参阅我的实验

但...

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

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) { ... }
}

碰巧一些正直的互联网用户创建了一个独立的 jar,其中包含提供服务RedBlue服务的 Guice 模块。所以我将 jar 添加到我的类路径并进行修改MyAppModule,以便我AwesomeService可以使用第三方RedBlue服务:

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

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

啊,但是该死,显然我的好互联网朋友决定不仅公开我需要的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);
}

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

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

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

或者我想我可以做一些诡计,错开绑定并隐藏它,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);
}

一定有更好的方法……还有……喷油器!

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

现在ExecutorService,两者都绑定和暴露,BlueModule不会RedModule污染我的,但我仍然可以得到我非常想要AwesomeService's ExecutorService的那些多汁BlueService和课程。RedService

希望这可以为其他人节省一些时间!

于 2013-04-26T07:18:40.530 回答