Spring源码-监听事件ApplicationListener和ApplicationEvent源码分析java
Spring中ApplicationListener和ApplicationEvent是典型的事件驱动模型,也就是咱们常说的发布-订阅模型 。其实咱们在开发中是常常用到这种发布-订阅模型模型的,发布订阅模型通常用在一对多的对象关系上,好比以下案例中,咱们就能用到这种发布-订阅模型。spring
案例:在用户注册成功后,每每还须要作其余事。多线程
一、加积分并发
二、发确认邮件app
三、若是是游戏账户,可能赠送游戏大礼包ide
四、索引用户数据源码分析
在如上案例中,若是咱们业务量不大的时候,其实能够直接用到Spring的发布-订阅模式就能解决,分别注册四个监听器,分别监听四个步骤,每个监听器去独立的作一件事;使用这种模式还能将代码解耦,还能结合多线程的优点来提供性能。post
1. 首先,咱们来初步使用如下Spring 的发布-订阅模式,以下是测试代码。性能
先在配置文件中配置MyListen和MyListen2二个监听器的Bean测试
<bean class="cn.edu.his.pay.listen.MyListen" /> <bean class="cn.edu.his.pay.listen.MyListen2" />
MyListen.java
package cn.edu.his.pay.listen; import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationListener; public class MyListen implements ApplicationListener { public void onApplicationEvent(ApplicationEvent arg0) { if(arg0 instanceof MyEvent) { MyEvent event = (MyEvent)arg0; System.out.println(this.getClass().getName() + event.getParam1()); System.out.println(this.getClass().getName() + event.getParam2()); System.out.println(this.getClass().getName() + event.getSource()); } } }
MyListen2.java
package cn.edu.his.pay.listen; import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationListener; public class MyListen2 implements ApplicationListener { public void onApplicationEvent(ApplicationEvent arg0) { if(arg0 instanceof MyEvent) { MyEvent event = (MyEvent)arg0; System.out.println(this.getClass().getName() + event.getParam1()); System.out.println(this.getClass().getName() + event.getParam2()); System.out.println(this.getClass().getName() + event.getSource()); } } }
MyEvent.java
package cn.edu.his.pay.listen; import org.springframework.context.ApplicationEvent; public class MyEvent extends ApplicationEvent { public String param1; public String param2; public MyEvent(Object source,String param1,String param2) { super(source); this.param1 = param1; this.param2 = param2; } public Object getSource() { return super.getSource(); } public String getParam1() { return param1; } public void setParam1(String param1) { this.param1 = param1; } public String getParam2() { return param2; } public void setParam2(String param2) { this.param2 = param2; } }
Test.java
@Test public void test() { // 往上下文context中发布事件 MyEvent event = new MyEvent("source","param1","param2"); context.publishEvent(event); }
输出结果
cn.edu.his.pay.listen.MyListenparam1 cn.edu.his.pay.listen.MyListenparam2 cn.edu.his.pay.listen.MyListensource cn.edu.his.pay.listen.MyListen2param1 cn.edu.his.pay.listen.MyListen2param2 cn.edu.his.pay.listen.MyListen2source
如上测试代码结果能够看出,经过自定义了一个MyEvent(主题)并发布到上下文中,这个时候只要有监听器订阅(观察者)就能拿到主题信息去完成本身的业务。
2. 而后咱们就须要思考,Spring是怎么作到的发布订阅了?如今咱们就结合Spring源码来分析。
先看看Spring在初始化的时候都作了什么? 入口:AbstractApplicationContext#registerListeners。
protected void registerListeners() { // Register statically specified listeners first. for (ApplicationListener<?> listener : getApplicationListeners()) { getApplicationEventMulticaster().addApplicationListener(listener); } // Do not initialize FactoryBeans here: We need to leave all regular beans // uninitialized to let post-processors apply to them! String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false); for (String lisName : listenerBeanNames) { getApplicationEventMulticaster().addApplicationListenerBean(lisName); } }
经过上面代码能够看出,在容器初始化的时候会将全部实现了ApplicationListener接口类beanName都先注册applicationListenerBeans集合中,至关于注册了全部的监听器。
其次,咱们再看看发布主题的时候context.publishEvent(event) 都作了什么?入口:AbstractApplicationContext#publishEvent(ApplicationEvent event)。
@Override public void publishEvent(ApplicationEvent event) { Assert.notNull(event, "Event must not be null"); if (logger.isTraceEnabled()) { logger.trace("Publishing event in " + getDisplayName() + ": " + event); } getApplicationEventMulticaster().multicastEvent(event); if (this.parent != null) { this.parent.publishEvent(event); } }
@Override @SuppressWarnings({ "unchecked", "rawtypes" }) public void multicastEvent(final ApplicationEvent event) { for (final ApplicationListener listener : getApplicationListeners(event)) { Executor executor = getTaskExecutor(); if (executor != null) { executor.execute(new Runnable() { @Override public void run() { listener.onApplicationEvent(event); } }); } else { listener.onApplicationEvent(event); } } }
经过如上代码其实能够看出,在发布事件(主题)的时候,先经过getApplicationListeners(event)获取了全部监听器(观察者),其实就是从以前Spring启动时候注册到applicationListenerBeans集合中取就行。取出全部的监听器(观察者),循环遍历去调用监听器(观察者)onApplicationEvent方法。