我正在使用Guava为发布-订阅消息服务创建EventBus
。我也在尝试第一次使用Guice。我已经阅读了Guice教程,并且一直在玩AbstractModule
和Binder
类。但是,当我离开教程并尝试为我的项目实际工作的那一刻,我很king。
我的项目有一个EventMonitor
,它将带有Guice注入的Guava EventBus
实例:
public class EventMonitor {
@Inject
private EventBus guavaEventBus;
// ...
}
在我的应用程序的Guice / DI / Bootstrapping代码中,我定义了
AbstractModule
构想:public class MyAppModule extends AbstractModule {
@Override
public void configure() {
// Here is where I want to wire together the EventBus to give
// to the EventMonitor.
}
}
最终,我想要一个通常以如下方式构造(在非Guice代码中)的
EventBus
:ThreadFactory factory = ThreadManager.currentRequestThreadFactory();
Executor executor = Executors.newCachedThreadPool(factory)
EventBus eventBus = new AsyncEventBus(executor);
我之所以感到窒息,是因为
ThreadManager
和Executors
上有两个(看似不可注入的)静态方法,并且因为我的引用是针对EventBus
的,但实际的对象却是AsynEventBus
;因此我不确定如何绑定它:// Doesn't work because how does Guice know I'm referencing an AsyncEventBus?!?
bind(EventBus.class).toInstance(executor);
// Doesn't work because now I've lost the ability to pass the
// AsyncEventBus an 'executor' and no-arg ctor is used!
bind(EventBus.class).to(AsyncEventBus.class);
因此,我问:考虑到我要构造
EventBus
的方式,一位身穿战衣的Guice退伍军人如何在这里连接东西(使用ThreadFactory
,Executor
和EventBus
),以便EventMonitor
,是否已正确配置完全配置的EventBus
?我认为一旦看到这个更“复杂”的示例,我就会开始通过树木看到森林。提前致谢。 最佳答案
身穿战衣的Guice退伍军人怎么会把这里的东西
两个词:提供者方法。
public class MyAppModule extends AbstractModule {
@Override
public void configure() {
bind(EventBus.class).to(AsyncEventBus.class);
}
@Provides @Singleton
ThreadFactory providesThreadFactory() {
return ThreadManager.currentRequestThreadFactory();
}
@Provides @Singleton
Executor providesExecutor(ThreadFactory factory) {
return Executors.newCachedThreadPool(factory)
}
@Provides @Singleton
AsyncEventBus providesAsyncEventBus(Executor executor) {
return new AsyncEventBus(executor);
}
}
命名以“ provides”开头的
@Provides
方法的约定不是guice所需要的,而是您真正想要做的,尤其是在大型代码库上。能够在代码体中搜索“提供”并找到提供特定对象的方法。在注释中回答问题的一些注意事项:
Guice检查为
Module
方法安装的每个@Provides
实例,并像将.toProvider
方法的返回类型绑定到匿名Provider
实例一样安装它们。因此,关于它们的妙处在于,您无需在configure
方法内使用任何其他代码即可使用它们。@Singleton
注释告诉guice您只需要该实例的一个实例,因此它将仅调用provides*
方法一次。如果不使用它,则默认情况是每次需要注入实例时,guice都会调用提供者和/或实例化一个新对象(取决于您为该类配置的对象)。注意:有些人在第一次发现这个问题时会大吃一惊,然后又想将@Singleton
放在各处以“提高效率”-这是不正确的反应。实际上,您确实想少量使用@Singleton
,并且仅在有多个不同实例的情况下才使用。在这种情况下,我们要非常确定周围只有一个
EventBus
。只要您不直接将Executor
或ThreadFactory
注入任何其他类中,就可以将这些方法的注释省略。对于ThreadFactory
几乎可以肯定不会有什么不同,因为我认为ThreadManager.currentRequestThreadFactory()
每次每次调用都会返回相同的实例。这对于Executor
会有所不同,但是也许您想要在其他使用它的其他地方新建一个Executor
实例?@Provides
方法的参数的连接方式与其余配置相同。例如,在这种情况下,我知道providesAsyncEventBus
将获得Executor
返回的providesExecutor
,因为只要请求Executor
,实例guice就会注入该实例。如果我有两个这样的方法:@Provides @Singleton
Executor providesExecutor1(ThreadFactory factory) {
return Executors.newCachedThreadPool(factory)
}
@Provides @Singleton
Executor providesExecutor2(ThreadFactory factory) {
return Executors.newScheduledThreadPool(10, factory)
}
然后,当您尝试创建注射器时,guice会引发配置错误,因为您已告诉guice使用两种不同的方法来获取
Executor
。现在,如果我有这样的事情:@Provides @Singleton
ExecutorService providesExecutor1(ThreadFactory factory) {
return Executors.newCachedThreadPool(factory)
}
@Provides @Singleton
ScheduledExecutorService providesExecutor2(ThreadFactory factory) {
return Executors.newScheduledThreadPool(10, factory)
}
但仍然具有上述
providesAsyncEventBus
方法,那么当您尝试创建注射器时,guice会引发错误,因为您没有告诉它如何创建Executor
所需的providesAsyncEventBus
。您需要附加一行,例如:bind(Executor.class).to(ExecutorService.class);
在您的
configure
方法中解决该问题。至于
register
方法,您有几种选择。我认为到目前为止,最简单的方法是将EventBus
参数添加到需要注册的对象的@Inject
注释的构造函数中,然后将evtBus.register(this)
作为构造函数的最后一行。其他选项包括使用静态注入(您可以阅读,但我不推荐),或使用multibinders将
Set<Object>
与适当的注释绑定,然后在创建Injector
的同一启动代码中进行迭代设置为注册任何东西。 (第二种方法可以用一些不错的模式来完成,但是直到您了解有关更简单的guice使用模式的更多信息后,我才建议您使用它)关于java - Guice:将具有复杂创建模式的bean连接起来,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/14668968/