事件监听器

Spring事件体系包括事件事件监听器事件广播器三个组件,实现原理其实就是观察者模式。Spring内置事件由系统内部进行发布,只需要注入监听器即可:

  • ContextRefreshedEvent:当容器被实例化所有Bean都已被加载后置处理器都被激活,所有单例bean都已被实例化,所有容器对象都已准备好可使用,如调用refresh()方法。若容器支持热重载,则refresh可以被触发多次,XmlWebApplicatonContext支持热刷新,GenericApplicationContext不支持。
  • ContextStartedEvent:当容器启动时发布,即调用start()方法,即所有Lifecycle Bean都已显式接收到了start信号
  • ContextStoppedEvent:当容器停止时发布,即调用stop()方法,即所有Lifecycle Bean都已显式接收到了stop信号,关闭的容器可通过start()方法重启
  • ContextClosedEvent:当容器关闭时发布,即调用close()方法,即所有单例Bean都已被销毁。关闭的容器不能被重启或refresh
  • RequestHandledEvent:只在使用Spring DispatcherServlet时有效,当一个请求被处理完成时发布

Spring事件机制是观察者模式的一种实现,除了发布者监听者者两个角色之外,还有一个EventMultiCaster的角色负责把事件转发给监听者,发布者调用context.publishEvent(msg),会将事件发送给了EventMultiCaster, 而EventMultiCaster注册着所有的Listener,然后根据事件类型决定转发给那个Listener。

源码

refresh()中的prepareRefresh()方法中创建了一个早期事件监听器对象earlyApplicationListeners,以及用于保存早期待发布的事件集合earlyApplicationEvents事件监听器还没有注册到多播器上的时候都称为早期事件。早期事件不需要手动publishEvent发布,在registerListeners中会自动发布,发布完早期事件后会将早期事件置空

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {
private Set<ApplicationEvent> earlyApplicationEvents;
private ApplicationEventMulticaster applicationEventMulticaster;
private Set<ApplicationListener<?>> earlyApplicationListeners;
protected void prepareRefresh() {
if (this.earlyApplicationListeners == null) { // 创建一个早期事件监听器对象
this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
} else {
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}
this.earlyApplicationEvents = new LinkedHashSet<>();
}
}

事件广播器初始化

applicationEventMulticaster提供了容器监听器的注册表refresh()中的initApplicationEventMulticaster()中会对事件广播器进行初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory(); // 获取我Bean工厂对象
// 判断容器中是否有applicationEventMulticaster应用多播器组件
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
// 直接显示的调用getBean获取ApplicationEventMulticaster赋值给applicationContext对象
this.applicationEventMulticaster = beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
} else { // 若容器中没有
// spring ioc显示的new一个SimpleApplicationEventMulticaster对象保存在applicatoinContext对象中
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
// 并且注入到容器中
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
}
}

用户可通过实现ApplicationEventMulticaster接口自定义事件广播器,Spring会将其注册成容器的事件广播器,若没有找到配置的外部事件广播器,默认使用SimpleApplicationEventMulticaster作为事件广播器。

注册事件监听器

refresh()的registerListeners()中会获取容器中所有的监听器对象,把监听器挨个的注册到多播器上去,这个时候正常流程是不会有监听器的,在initApplicationEventMulticaster之后,在registerListeners之前,只有一个可能onRefresh()里面注册了监听器。这里会执行所有的早期发布事件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
protected void registerListeners() {
// 获取容器中所有的监听器对象,把监听器挨个的注册到多播器上去,这个时候正常流程是不会有监听器的
// 监听器不会在这之前注册,在initApplicationEventMulticaster后在registerListeners之前,只有一个可能在:在onRefresh里面注册了监听器
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
// 获取Bean定义中的监听器对象
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) { // 把监听器的名称注册到多播器上
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
// 获取早期事件
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null; // 在这里赋null,也就是值此之后都将没有早期事件了
if (earlyEventsToProcess != null) {// 通过多播器进行播发早期事件
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}

这里只是把监听器的名称注册到多播器上,为了防止懒加载的监听器漏掉,因为懒加载的Bean是不会在容器初始化时加载的,只会在使用时才会去加载,且这里只处理实现了ApplicationListener接口的监听器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
private class ListenerRetriever {
// 存储了所有的Listener,包括实现了ApplicationListener接口和使用了@EventListener的Bean
public final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();
// 只存储实现了ApplicationListener接口的Bean名称
public final Set<String> applicationListenerBeans = new LinkedHashSet<>();
private final boolean preFiltered;
public ListenerRetriever(boolean preFiltered) {
this.preFiltered = preFiltered;
}
public Collection<ApplicationListener<?>> getApplicationListeners() {
List<ApplicationListener<?>> allListeners = new ArrayList<>(this.applicationListeners.size() + this.applicationListenerBeans.size());
allListeners.addAll(this.applicationListeners);
if (!this.applicationListenerBeans.isEmpty()) {
BeanFactory beanFactory = getBeanFactory();
for (String listenerBeanName : this.applicationListenerBeans) {
try {
ApplicationListener<?> listener = beanFactory.getBean(listenerBeanName, ApplicationListener.class);
if (this.preFiltered || !allListeners.contains(listener)) {
allListeners.add(listener);
}
} catch (NoSuchBeanDefinitionException ex) {
}
}
}
if (!this.preFiltered || !this.applicationListenerBeans.isEmpty()) {
AnnotationAwareOrderComparator.sort(allListeners);
}
return allListeners;
}
}

发布事件

Spring委托ApplicationEventMulticaster将事件通知给所有的事件监听器,这里会发布ContextRefreshedEvent事件,可实现一个ContextRefreshedEvent事件的监听器做一些扩展。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
protected void finishRefresh() {
// 清除上下文级别的资源缓存,如来自扫描的ASM元数据
clearResourceCaches();
// 注册lifecycleProcessor声明周期处理器,作用:当ApplicationContext启动或停止时,它会通过LifecycleProcessor来与所有声明的bean的周期做状态更新
initLifecycleProcessor();
// 为实现了SmartLifecycle并且isAutoStartup 自动启动的Lifecycle调用start()方法
getLifecycleProcessor().onRefresh();
// 发布容器启动完毕事件
publishEvent(new ContextRefreshedEvent(this));
// 注册当前spring容器到LiveBeansView,提供servlet(LiveBeansViewServlet)在线查看所有的bean json 、 为了支持Spring Tool Suite的智能提示
LiveBeansView.registerApplicationContext(this);
}
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {
public void publishEvent(ApplicationEvent event) {
publishEvent(event, null);
}
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
Assert.notNull(event, "Event must not be null");
ApplicationEvent applicationEvent;
if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent) event;
} else {
applicationEvent = new PayloadApplicationEvent<>(this, event);
if (eventType == null) {
eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
}
}
// 这里是唯一添加早期事件的地方,所以一定要发布事件才能添加早期事件
// 只有当执行力refresh-->registerListeners才会将earlyApplicationEvents赋为null,故registerListeners之前发布的事件都是早期事件
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
} else {
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
}
if (this.parent != null) { // 若是父容器,也会向父容器里广播一份
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
} else {
this.parent.publishEvent(event);
}
}
}
}

Spring默认的事件广播器为SimpleApplicationEventMulticaster,这里其实就是挨个去调用事件监听器的onApplicationEvent方法。默认getTaskExecutor()获取的线程池为null,故默认是同步执行applicationContext.publishEvent()方法需要同步等待各个监听器处理完之后才返回。若想异步可实现ApplicationEventMulticaster接口,并将其注册beanNameapplicationEventMulticaster的Bean。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
// 从多播器中获取出所有的监听器
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
Executor executor = getTaskExecutor(); // 判断多播器中是否支持异步多播的
if (executor != null) { // 异步播发事件
executor.execute(() -> invokeListener(listener, event));
} else { // 同步播发
invokeListener(listener, event);
}
}
}
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
try {
doInvokeListener(listener, event);
} catch (Throwable err) {
errorHandler.handleError(err);
}
} else {
doInvokeListener(listener, event);
}
}
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
listener.onApplicationEvent(event);
} catch (ClassCastException ex) {
throw ex;
}
}
}

遍历注册的每个监听器,并启动来调用每个监听器的onApplicationEvent方法。由于SimpleApplicationEventMulticastertaskExecutor的实现类是SyncTaskExecutor,因此事件监听器对事件的处理是同步进行的。

自定义监听器注册

对于用户自定义的监听器的解析是通过ApplicationListenerDetector后置处理器来实现的,该Bean后置处理器是在refresh()的registerBeanPostProcessors(beanFactory)中注册的,在第八次Bean的后置处理器的调用的地方调用。用于解析实现了ApplicationListener接口的方式的监听器

1
2
3
4
5
6
7
8
9
10
11
12
13
class ApplicationListenerDetector implements DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor {
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean instanceof ApplicationListener) {
Boolean flag = this.singletonNames.get(beanName);
if (Boolean.TRUE.equals(flag)) {
this.applicationContext.addApplicationListener((ApplicationListener<?>) bean);
} else if (Boolean.FALSE.equals(flag)) {
this.singletonNames.remove(beanName);
}
}
return bean;
}
}

对于注解方式的自定义监听器的解析与执行是通过在IoC容器启动最开始时在AnnotatedBeanDefinitionReader中注册了一系列创世纪的类时,注册了DefaultEventListenerFactory事件监听器工厂和处理监听方法的注解@EventListener解析器EventListenerMethodProcessor。解析是在refresh()的finishBeanFactoryInitialization(beanFactory)的beanFactory.preInstantiateSingletons()中,且是在所有单例Bean都已实例化完成加载到单例池中之后:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public void preInstantiateSingletons() throws BeansException {
// 获取容器中所有bean定义的名称
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// 所有的单实例的bean已经记载到单实例bean到缓存中
for (String beanName : beanNames) {
// 从单例缓存池中获取所有的对象
Object singletonInstance = getSingleton(beanName);
// 判断当前的bean是否实现了SmartInitializingSingleton接口
if (singletonInstance instanceof SmartInitializingSingleton) {
final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
} else {
// 触发实例化之后的方法afterSingletonsInstantiated
smartSingleton.afterSingletonsInstantiated();
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
public class EventListenerMethodProcessor implements SmartInitializingSingleton, ApplicationContextAware {
protected final Log logger = LogFactory.getLog(getClass());
private final EventExpressionEvaluator evaluator = new EventExpressionEvaluator();
// 没有@EventListener的类
private final Set<Class<?>> nonAnnotatedClasses = Collections.newSetFromMap(new ConcurrentHashMap<>(64));
@Nullable
private ConfigurableApplicationContext applicationContext;
private ConfigurableApplicationContext getApplicationContext() {
Assert.state(this.applicationContext != null, "No ApplicationContext set");
return this.applicationContext;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
Assert.isTrue(applicationContext instanceof ConfigurableApplicationContext, "ApplicationContext does not implement ConfigurableApplicationContext");
this.applicationContext = (ConfigurableApplicationContext) applicationContext;
}

@Override
public void afterSingletonsInstantiated() {
// 从BeanFactory中获取EventListenerFactory的bean默认情况下的两个实现,DefaultEventListenerFactory:spring自己注入的,TransactionalEventListenerFactory:使用配置进去的
List<EventListenerFactory> factories = getEventListenerFactories();
ConfigurableApplicationContext context = getApplicationContext();
String[] beanNames = context.getBeanNamesForType(Object.class);
for (String beanName : beanNames) { // 处理所有bean查找当前bean标注了@EventListener的方法
if (!ScopedProxyUtils.isScopedTarget(beanName)) {
Class<?> type = null;
try {
type = AutoProxyUtils.determineTargetClass(context.getBeanFactory(), beanName);
} catch (Throwable ex) {
}
if (type != null) {
if (ScopedObject.class.isAssignableFrom(type)) {
try {
Class<?> targetClass = AutoProxyUtils.determineTargetClass(context.getBeanFactory(), ScopedProxyUtils.getTargetBeanName(beanName));
if (targetClass != null) {
type = targetClass;
}
} catch (Throwable ex) {
}
}
try {
processBean(factories, beanName, type);
} catch (Throwable ex) {
throw new BeanInitializationException("Failed to process @EventListener " + "annotation on bean with name '" + beanName + "'", ex);
}
}
}
}
}
protected List<EventListenerFactory> getEventListenerFactories() {
Map<String, EventListenerFactory> beans = getApplicationContext().getBeansOfType(EventListenerFactory.class);
List<EventListenerFactory> factories = new ArrayList<>(beans.values());
AnnotationAwareOrderComparator.sort(factories);
return factories;
}
protected void processBean(final List<EventListenerFactory> factories, final String beanName, final Class<?> targetType) {
if (!this.nonAnnotatedClasses.contains(targetType)) {
Map<Method, EventListener> annotatedMethods = null;
try { // 查找当前bean标注了@EventListener的方法
annotatedMethods = MethodIntrospector.selectMethods(targetType, (MethodIntrospector.MetadataLookup<EventListener>) method -> AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class));
} catch (Throwable ex) {
}
if (CollectionUtils.isEmpty(annotatedMethods)) {
this.nonAnnotatedClasses.add(targetType);
} else {
ConfigurableApplicationContext context = getApplicationContext();
for (Method method : annotatedMethods.keySet()) {
for (EventListenerFactory factory : factories) {
if (factory.supportsMethod(method)) { // ①创建事件监听器
Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));
ApplicationListener<?> applicationListener = factory.createApplicationListener(beanName, targetType, methodToUse);
if (applicationListener instanceof ApplicationListenerMethodAdapter) {
((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);
}
context.addApplicationListener(applicationListener); // ②注册事件到Context中
break;
}
}
}
}
}
}
}

注解方式的监听器发布事件是统一走的ApplicationListenerMethodAdapteronApplicationEvent方法,然后通过反射来调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class ApplicationListenerMethodAdapter implements GenericApplicationListener {
public void onApplicationEvent(ApplicationEvent event) {
processEvent(event);
}
public void processEvent(ApplicationEvent event) {
Object[] args = resolveArguments(event);
if (shouldHandle(event, args)) {
Object result = doInvoke(args);
if (result != null) {
handleResult(result);
}
}
}
protected Object doInvoke(Object... args) {
Object bean = getTargetBean();
ReflectionUtils.makeAccessible(this.method);
try {
return this.method.invoke(bean, args);
}
}
}

自定义事件

事件类继承ApplicationEvent即可

1
2
3
4
5
6
7
8
9
10
public class ElevenEvent extends ApplicationEvent {
private String name;
public ElevenEvent(Object source, String name) {
super(source);
this.name = name;
}
public String getName() {
return name;
}
}

监听器可以基于接口,需实现ApplicationListener接口覆写onApplicationEvent方法,也可基于@EventListener注解的方式,同一个事件可有多个监听器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Component
public class ElevenEventListener implements ApplicationListener<ElevenEvent> {
@Override
public void onApplicationEvent(ElevenEvent event) {
System.out.println(Thread.currentThread().getName() + ", Interface:" + event.getName());
}
}
@Component
public class ElevenEventAnnotationListener {
@EventListener(value = ElevenEvent.class)
public void onApplicationEvent(ElevenEvent event) {
System.out.println(Thread.currentThread().getName() + ", Annotation:" + event.getName());
}
}

事件的发布通过容器发布即可

1
2
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
context.publishEvent(new ElevenEvent(context, "test"));

事件监听操作可异步执行,只需配置异步线程池即可

1
2
3
4
5
6
@Bean(name = "applicationEventMulticaster")
public ApplicationEventMulticaster simpleApplicationEventMulticaster() {
SimpleApplicationEventMulticaster eventMulticaster = new SimpleApplicationEventMulticaster();
eventMulticaster.setTaskExecutor(new SimpleAsyncTaskExecutor());
return eventMulticaster;
}