Java Guice:用复杂的创作模式连接bean
我正在使用Guava为发布-订阅消息服务创建一个Java Guice:用复杂的创作模式连接bean,java,dependency-injection,guice,Java,Dependency Injection,Guice,我正在使用Guava为发布-订阅消息服务创建一个EventBus。我也第一次尝试使用Guice。我已经阅读了Guice教程,并且一直在使用AbstractModule和Binder类。但是,当我离开教程并试图为我的项目做点什么的时候,我就窒息了 我的项目有一个EventMonitor,它将有一个Guice注入的GuavaEventBus实例: public class EventMonitor { @Inject private EventBus guavaEventBus;
EventBus
。我也第一次尝试使用Guice。我已经阅读了Guice教程,并且一直在使用AbstractModule
和Binder
类。但是,当我离开教程并试图为我的项目做点什么的时候,我就窒息了
我的项目有一个EventMonitor
,它将有一个Guice注入的GuavaEventBus
实例:
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.
}
}
最后,我想要一个EventBus
,它通常是这样构造的(在非Guice代码中):
我之所以窒息,是因为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检查您为
@安装的每个
模块
实例,提供
方法,并将其安装为将方法的返回类型与
绑定到匿名.toProvider
提供程序
实例。因此,它们的优点在于,在
方法中不需要任何额外的代码就可以使用它们configure
注释告诉guice您只需要该对象的一个实例,因此它只调用@Singleton
方法一次。默认情况下,如果您不使用它,则每次需要注入实例时,guice都会调用您的提供程序和/或实例化一个新对象(取决于您为该类配置的内容)。注意:有些人在第一次发现这一点时会发疯,然后想把提供的*
放在任何地方“为了效率”——这是一种不恰当的反应。实际上,您确实希望节省地使用@Singleton
,并且只在有多个不同实例的情况下使用 在本例中,我们希望确保只有一个@Singleton
。只要不直接将EventBus
或Executor
注入任何其他类,就可以不使用这些方法。对于ThreadFactory
来说,这几乎肯定不会有什么不同,因为我认为ThreadFactory
每次调用时都返回相同的实例。这将对ThreadManager.currentRequestThreadFactory()
产生影响,但也许您希望在其他使用它的地方有一个新的Executor
实例Executor
方法的参数与其余配置的连接方式相同。例如,在本例中,我知道@提供的
将获得由providesacynceventbus
返回的providesecutor
,因为每当请求Executor
时,实例guice都将注入该实例。如果我有两种这样的方法:Executor
@Provides @Singleton Executor providesExecutor1(ThreadFactory factory) { return Executors.newCachedThreadPool(factory) } @Provides @Singleton Executor providesExecutor2(ThreadFactory factory) { return Executors.newScheduledThreadPool(10, factory) }
然后,当您尝试创建注入器时,guice会抛出一个配置错误,因为您已经告诉guice使用两种不同的方法来获取@Provides @Singleton ExecutorService providesExecutor1(ThreadFactory factory) { return Executors.newCachedThreadPool(factory) } @Provides @Singleton ScheduledExecutorService providesExecutor2(ThreadFactory factory) { return Executors.newScheduledThreadPool(10, factory) }
执行器。现在,如果我有这样的东西:
@Provides @Singleton Executor providesExecutor1(ThreadFactory factory) { return Executors.newCachedThreadPool(factory) } @Provides @Singleton Executor providesExecutor2(ThreadFactory factory) { return Executors.newScheduledThreadPool(10, factory) }
但是仍然有如上所述的@Provides @Singleton ExecutorService providesExecutor1(ThreadFactory factory) { return Executors.newCachedThreadPool(factory) } @Provides @Singleton ScheduledExecutorService providesExecutor2(ThreadFactory factory) { return Executors.newScheduledThreadPool(10, factory) }
方法,那么guice在尝试创建注入器时会抛出一个错误,因为您没有告诉它如何创建providesAsyncEventBus
所需的providesAsyncEventBus
。您需要添加一行,如:Executor
在bind(Executor.class).to(ExecutorService.class);
中,配置
方法以解决问题
- 至于你的
方法,你有几个选择。我认为到目前为止最简单的方法是向需要注册的对象的注册
-注释构造函数添加@Inject
参数,然后执行EventBus
作为构造函数的最后一行 其他选项包括使用静态注入(您可以阅读,但我不推荐),或使用多绑定器将evtBus。注册(此)
与适当的注释绑定,然后在创建集
注入器的同一启动代码中,迭代该集以注册任何内容。(第二种方法可以在一些很好的模式中实现,但在您了解更多关于更简单的guice使用模式之前,我不会推荐它)
@Singleton
?如果我没有在所有这些提供者上指定它,会发生什么?其次,EventBus
对象上有一个register(object)
方法,我在其中注册所有不同的“事件侦听器”。我在哪里进行这些register
调用?我假设,如果我想要相同的,singleton甚至