本篇主要来聊一聊spring中ApplicationListener接口和ApplicationEvent类。
从命名上可以很容易的看出来一个是listener另一个是被监听的事件,但是spring是如何做到listener去监听event?同时我们该如何在日常开发过程中使用spring为我们提供的这一个监听模式?
0x01 listener和event关系
spring启动后会为我们创建好一个上下文,也即是我们经常听到的spring IOC的上下文ApplicationContext,可以理解ApplicationContext中是初始化了所有在.xml文件配置的bean标签的bean。
我们通过在.xml文件中定义一个listener的bean,这个listener用来监听event,listener通过实现方法com.boyu.budmw.test.AppListener#onApplicationEvent来对event进行处理。
listener准备好了我们可以开始向ApplicationContext中发布event,当event发布后,所有在ApplicationContext中的listener都会收到对应的event。
0x02 如何使用listener和event这一特性
定义event
首先我们要定义一个event,不然拿什么来触发?public class AppEvent extends ApplicationEvent { public AppEvent(Object source) { super(source); } public void sayHi(){ System.out.println("sayHi"); } }
定义一个event非常简单,但是需要注意,这里一定要实现带有一个参数的构造函数,因为父类ApplicationEvent中没有默认的构造方法,所以子类必须重载构造函数。
定义listener
public class AppListener implements ApplicationListener { public void onApplicationEvent(ApplicationEvent event) { if(!(event instanceof AppEvent)){ return ; } AppEvent appEvent = (AppEvent)event; appEvent.sayHi(); } }
上面是一个listener的实现类,listener类必须实现ApplicationListener接口,同时要实现接口中的onApplicationEvent方法,这个方法会接收到一个event,然后可以对这个event进行处理了。
将listener类注入到spring的ApplicationContext中。<bean id="appListener" class="com.boyu.budmw.test.AppListener" />
测试listener和event
public class ListenerTest { public static void main (String args[]){ ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:/config/applicationContext.xml"); AppEvent appEvent = new AppEvent("appEvent"); applicationContext.publishEvent(appEvent); } }
通过org.springframework.context.ApplicationEventPublisher#publishEvent方法将event发布到spring应用上下文中,同时这个动作会触发listener收到event事件。
0x03 深入剖析发布与监听的过程
在使用org.springframework.context.ApplicationEventPublisher#publishEvent方法发布event的时候,最终会调用到spring中的org.springframework.context.event.SimpleApplicationEventMulticaster类的如下的一段代码。
当然这也是取决于你有没有对applicationEventMulticaster进行定制,如果定制了,会走到你自己定制的逻辑,下面这段是spring默认的一段逻辑。
public void multicastEvent(final ApplicationEvent event) {
for (final ApplicationListener listener : getApplicationListeners(event)) {
Executor executor = getTaskExecutor();
if (executor != null) {
executor.execute(new Runnable() {
@SuppressWarnings("unchecked")
public void run() {
listener.onApplicationEvent(event);
}
});
}
else {
listener.onApplicationEvent(event);
}
}
}
这段代码一看挺简单,通过org.springframework.context.event.AbstractApplicationEventMulticaster#getApplicationListeners(org.springframework.context.ApplicationEvent)这个方法获得applicationContext中所有的listener,然后依次调用各个listener。
getApplicationListeners这个方法中的逻辑是从beanFactory中获取所有的ApplicationListener对象。
0x04 这个特性有什么用?
当然这里也只能谈谈自己认识到的应用场景,event中可以定义一些复杂的对象或者叫服务,这样服务提供者就和服务的使用者彻底解耦了。
根据自己的业务场景可以做很多事情,期待你的补充。
0x05 参考
这篇我想最有参考价值的东西还是spring的源码,可以去调试相关的代码。spring有很多有价值或者说值得学习的设计思想,同样编码的规范也可以让你学到很多,多多跟着自己的思维去调试spring源码。