概述
由Google
提供的Guava EventBus
是一个很不错的进程内事件总线机制。在非Spring
应用中,使用 Guava EventBus
是可以的,但各种组件,比如事件总线,事件监听器都是通过java new
关键字创建出来的。这种开发人员自己管理对象生命周期的方式,在Spring
应用中,就显得很不“Spring”,因为我们知道,Spring
应用一个很大的特点就在于所有对象实例都尽量由Spring IoC
容器来管理。本文先介绍一下非Spring
应用中Guava EventBus
一般的使用方式,然后再切换到Spring
应用的情景,看看如何以很“Spring”的方式使用Guava EventBus
。
非Spring
应用中使用Guava EventBus
事件总线的定义
// 使用Java new关键字创建事件总线对象
EventBus eventBus = new EventBus();
定义事件消费者逻辑
定义事件消费者逻辑其实是利用Guava
的注解@Subscribe
指定当某个事件发生时执行所制定的逻辑,如下所示 :
class StringEventListener{
// 当所注册到的事件总线上发生String消息时,会在控制台上输出相应的消息
@Subscribe
public void listener(String event) {
System.out.println("receive msg:"+event);
}
}
注册事件消费者逻辑到事件总线
注册事件消费者逻辑到事件总线其实是告诉事件总线,当某某事件发生时,你要去执行我告诉你的逻辑。比如下面的例子,就是告诉事件总线对象eventBus
,一旦发生String
事件,你要调用方法事件监听器对象stringEventListener
的方法listener
。
// 注意 : 这里使用Java new关键字创建事件监听器对象
StringEventListener stringEventListener=new StringEventListener();
eventBus.register(stringEventListener);
事件生产者逻辑
下面的代码片段演示了消息生产者如何发布一个String
消息的,该消息会触发上面事件监听器对象stringEventListener
的方法listener
的执行。
// 在开发人员需要发布事件的地方,开发人员通过某种方式拿到eventBus对象,通常可能是利用参数传递,
// 或者全局变量方式得到,然后发布事件
eventBus.post("hello");
Spring
应用中使用Guava EventBus
事件总线的定义
// 该例子使用Spring注解@Configuration+@Bean的方式定义了一个事件总线bean,该bean最终的创建虽然使用了Java
// 关键字new,但整个bean的生命周期管理都托管给了Spring IoC容器,这是很“Spring”的应用方式,避免了开发人员自己
// 负责事件总线对象的生命周期管理
@Configuration
public class EventBusConfig {
//定义事件总线bean
@Bean
public EventBus eventBus() {
return new EventBus();
}
}
定义事件消费者逻辑
定义事件消费者逻辑其实是利用Guava
的注解@Subscribe
指定当某个事件发生时执行所制定的逻辑,如下所示 :
注意该例子跟非Spring
应用中使用Guava EventBus
时定义事件消费者逻辑的方式的区别:这里使用了Spring
的注解@Component
,该注解的作用是让Spring
把该类作为一个bean
定义注册到容器。
这种方式跟非Spring
应用中使用Guava EventBus
时定义事件消费者逻辑的方式区别的根本在于:开发人员不是自己在管理事件消费者对象的生命周期,而是交由Spring IoC
容器来管理。
@Component
class StringEventListener{
// 当所注册到的事件总线上发生String消息时,会在控制台上输出相应的消息
@Subscribe
public void listener(String event) {
System.out.println("receive msg:"+event);
}
}
注册事件消费者逻辑到事件总线
该方式和非Spring
应用中注册事件消费者逻辑到事件总线的方式也有很大不同,这里通过注解@Component
定义了一个bean
,并且他实现了Spring
的接口BeanPostProcessor
。利用这种方式,Spring IoC
首先会在容器中定义了一个bean eventSubscribeBeanPostProcessor
,然后在容器实例化其他每个bean
时,会对该bean
调用eventSubscribeBeanPostProcessor bean
的方法postProcessAfterInitialization()
,这样,我们就有一个机会来检测每个bean
是否是一个Guava @Subscribe
定义的事件监听器bean
,如果是,我们就可将该bean
注册到事件总线bean
eventBus
上。
@Component
public class EventSubscribeBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
return bean;
}
//对于每个容器执行了初始化的 bean,如果这个 bean 的某个方法注解了@Subscribe,则将该 bean 注册到事件总线
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
// for each method in the bean
Method[] methods = bean.getClass().getMethods();
for (Method method : methods) {
// check the annotations on that method
Annotation[] annotations = method.getAnnotations();
for (Annotation annotation : annotations) {
// if it contains the Subscribe annotation
if (annotation.annotationType().equals(Subscribe.class)) {
// 如果这是一个Guava @Subscribe注解的事件监听器方法,说明所在bean实例
// 对应一个Guava事件监听器类,将该bean实例注册到Guava事件总线
eventBus.register(bean);
return bean;
}
}
}
return bean;
}
// 事件总线bean由Spring IoC容器负责创建,这里只需要通过@Autowired注解注入该bean即可使用事件总线
@Autowired
EventBus eventBus;
}
事件生产者逻辑
// 在开发人员需要发布事件的地方,开发人员可以通过很“Spring”的方式拿到eventBus对象,比如通常是利用@Autowired
// 注解注入该事件总线对象 :
// @Autowired
// EventBus eventBus;
// 然后使用它发布事件 :
eventBus.post("hello");