我想在不引入注释或使用字符串键名的情况下完成以下操作,是否可以使用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*
,它使用MyService
和Red
以及它自己的Blue Services
:
ExecutorService
答案 0 :(得分:10)
TL; DR:将Blue
和Red
模块隔离到它们自己的注入器,并在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,它提供Red
和Blue
服务。因此,我将jar添加到我的类路径并修改MyAppModule
,以便我的AwesomeService
可以使用第三方Red
和Blue
服务:
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
需要的BlueService
和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);
}
啊,但该死的,我的ExecutorService
绑定是由我的私有包装器模块继承的,并且与RedModule
和BlueModule
中定义的内部绑定冲突。我想我可以在我的ExecutorService
构造函数中注释或命名我的AwesomeService
,但是如果我希望ExecutorService
成为我的应用程序共享的单例,那么20,30或40不同服务。我将不得不用这个注释污染我的所有ExecutorService
注射。
或者我想我可以做一些诡计,错开绑定并隐藏ExecutorService
,这样它就不会与ExecutorService
和RedModule
创建的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);
}
}
现在,ExecutorService
和BlueModule
中绑定和展示的RedModule
不会污染我的AwesomeService's
ExecutorService
,但我仍然可以获得我非常想要那些多汁的BlueService
和RedService
课程。
希望将来某个时候可以节省其他人的时间!