一、Spring事件发布监听的使用
ApplicationContext 通过 ApplicationEvent 类和 ApplicationListener 接口进行事件处理。 如果将实现 ApplicationListener 接口的 bean 注入到上下文中,则每次使用 ApplicationContext 发布 ApplicationEvent 时,都会通知该 bean。
Spring的事件(ApplicationEvent)其实就是一个观察者设计模式,一个 Bean 处理完成任务后希望通知其它 Bean 或者说 一个Bean 想观察监听另一个Bean的行为。
Spring事件只需要以下几步:
- 自定义事件,继承 ApplicationEvent
- 定义监听器,实现 ApplicationListener 或者通过 @EventListener 注解到方法上
- 定义发布者,通过 ApplicationEventPublisher发布事件
自定义事件
@Getter
public class Extend_ApplicationEvent extends ApplicationEvent {
String msg;
public Extend_ApplicationEvent(Object source, String msg) {
super(source);
this.msg = msg;
}
}
定义监听器
实现 ApplicationListener
@Component
public class Extend_ApplicationListener implements ApplicationListener<ApplicationEvent> {
@Override
public void onApplicationEvent(ApplicationEvent event) {
System.out.println("收到事件:" + event);
}
}
@EventListener 注解
@Component
public class Extend_EventListener {
@EventListener(classes = {ApplicationEvent.class})
public void listener(ApplicationEvent event) {
System.out.println("注解事件监听..." + event);
}
}
定义发布者
ApplicationEventPublisher发布
@Component
public class Extend_ApplicationEventPublisher {
@Autowired
ApplicationEventPublisher applicationEventPublisher;
public void publishEvent(ApplicationEvent event) {
applicationEventPublisher.publishEvent(event);
}
}
ApplicationContext发布
@Test
public void test01() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Extend_Config.class);
Extend_ApplicationEventPublisher applicationEventPublisher = applicationContext.getBean(Extend_ApplicationEventPublisher.class);
// 发布自定义事件
applicationContext.publishEvent(new Extend_ApplicationEvent("applicationContext事件","wei"));
//
applicationEventPublisher.publishEvent(new Extend_ApplicationEvent("applicationEventPublisher事件","wei2"));
applicationContext.close();
}
示例输出:
收到事件:org.springframework.context.event.ContextRefreshedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@327471b5, started on Thu Aug 31 17:34:44 CST 2023]
注解事件监听...org.springframework.context.event.ContextRefreshedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@327471b5, started on Thu Aug 31 17:34:44 CST 2023]
收到事件:com.wei.spring.extend_07.Extend_ApplicationEvent[source=applicationContext事件]
注解事件监听...com.wei.spring.extend_07.Extend_ApplicationEvent[source=applicationContext事件]
收到事件:com.wei.spring.extend_07.Extend_ApplicationEvent[source=applicationEventPublisher事件]
注解事件监听...com.wei.spring.extend_07.Extend_ApplicationEvent[source=applicationEventPublisher事件]
收到事件:org.springframework.context.event.ContextClosedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@327471b5, started on Thu Aug 31 17:34:44 CST 2023]
注解事件监听...org.springframework.context.event.ContextClosedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@327471b5, started on Thu Aug 31 17:34:44 CST 2023]
看到有4个事件被监听消费,ContextRefreshedEvent、两个自定义Extend_ApplicationEvent、ContextClosedEvent事件。
事件的创建顺序和时机如下:
1)ContextRefreshedEvent:
容器创建时,finishRefresh() 后容器刷新完成会发布 ContextRefreshedEvent
2)自定义事件
3)ContextClosedEvent:
容器关闭会创建 ContextClosedEvent
二、事件发布监听的原理
2.1 事件发布的流程
发布自定义事件
applicationContext.publishEvent(new Extend_ApplicationEvent(“applicationContext事件”,“wei”));
void publishEvent(Object event, @Nullable ResolvableType eventType) {
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
}
1)获取事件的多播器(派发器):getApplicationEventMulticaster()
2)multicastEvent() 派发事件
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();
// 获取该事件对应的所有的 ApplicationListener
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
// 存在 Executor 则异步执行,否则同步执行
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}
invokeListener()方法即为执行listener.onApplicationEvent()方法;
invokeListener(listener, event); -> doInvokeListener(listener, event); -> listener.onApplicationEvent(event);
2.2 事件的多播器
容器创建的refresh() ——> initApplicationEventMulticaster(); 初始化事件多播器
1)先去容器中查找ID为 “applicationEventMulticaster” 的组件
2)如果没有这初始化创建多播器 ,并加到容器中,就可以在其他组件需要派发事件时,自动注入这个 applicationEventMulticaster
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// 容器中查找ID为 "applicationEventMulticaster" 的组件
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isTraceEnabled()) {
logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
else {
// 没有这初始化创建多播器
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
// 注册到容器中,ID为 applicationEventMulticaster
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isTraceEnabled()) {
logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
}
}
}
2.3 容器中的监听器
容器创建的refresh() -> registerListeners(); 注册监听器
1)从容器中拿到所有的监听器 ApplicationListener.class
2)把他们注册到 applicationEventMulticaster (事件多播器)中
protected void registerListeners() {
// Register statically specified listeners first.
// 首先注册 applicationListeners 中的监听器
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!
// 从容器中拿到所有的监听器 ApplicationListener.class
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
// 2)把他们注册到 applicationEventMulticaster (事件多播器)中
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
// Publish early application events now that we finally have a multicaster...
// 发布一些前置事件
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
2.4 @EventListener 事件监听注解
使用 @EventListener 事件监听注解,是未实现 ApplicationListener 接口的,那他是如何实现事件的监听呢?
Spring采用了一个后置处理器来处理事件监听注解,使用 EventListenerMethodProcessor 处理器来解析方法上的 @EventListener
public class EventListenerMethodProcessor
implements SmartInitializingSingleton, ApplicationContextAware, BeanFactoryPostProcessor {}
其实现了三个接口,ApplicationContextAware, BeanFactoryPostProcessor对于applicationContext和beanFactory信息的设置,【重点】在于其重写的 SmartInitializingSingleton afterSingletonsInstantiated()方法。
ps:其执行阶段在单例预实例化阶段结束时调用,并保证所有常规单例bean都已创建;
SmartInitializingSingleton 的执行原理及时机
1)refresh() -> finishBeanFactoryInitialization(beanFactory);
2)beanFactory.preInstantiateSingletons();
1)getBean(); 创建好所有的单实例bean
2)循环判断所有的bean 是否有属于 SmartInitializingSingleton 的子类
3)如果是则调用:smartSingleton.afterSingletonsInstantiated();
3)finishRefresh(); 容器刷新完成
然后来看一下EventListenerMethodProcessor 的 SmartInitializingSingleton afterSingletonsInstantiated()方法做了什么?
afterSingletonsInstantiated() ——> processBean(beanName, type);
processBean(beanName, type)的源码:
1)获取到所有 注解EventListener 的方法
2)如果注解EventListener 的方法不为空,则遍历将其转换为 ApplicationListener
3)将ApplicationListener添加至容器中
private void processBean(final String beanName, final Class<?> targetType) {
if (!this.nonAnnotatedClasses.contains(targetType) &&
AnnotationUtils.isCandidateClass(targetType, EventListener.class) &&
!isSpringContainerClass(targetType)) {
Map<Method, EventListener> annotatedMethods = null;
try {
// 获取到所有 注解EventListener 的方法
annotatedMethods = MethodIntrospector.selectMethods(targetType,
(MethodIntrospector.MetadataLookup<EventListener>) method ->
AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class));
}
catch (Throwable ex) {
// An unresolvable type in a method signature, probably from a lazy bean - let's ignore it.
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve methods for bean with name '" + beanName + "'", ex);
}
}
// 为空
if (CollectionUtils.isEmpty(annotatedMethods)) {
this.nonAnnotatedClasses.add(targetType);
if (logger.isTraceEnabled()) {
logger.trace("No @EventListener annotations found on bean class: " + targetType.getName());
}
}
else {
// 注解EventListener 的方法 不为空
// Non-empty set of methods
ConfigurableApplicationContext context = this.applicationContext;
Assert.state(context != null, "No ApplicationContext set");
List<EventListenerFactory> factories = this.eventListenerFactories;
Assert.state(factories != null, "EventListenerFactory List not initialized");
// 遍历所有的 注解EventListener方法
for (Method method : annotatedMethods.keySet()) {
for (EventListenerFactory factory : factories) {
if (factory.supportsMethod(method)) {
Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));
// 转换创建 ApplicationListener
ApplicationListener<?> applicationListener =
factory.createApplicationListener(beanName, targetType, methodToUse);
if (applicationListener instanceof ApplicationListenerMethodAdapter) {
((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);
}
context.addApplicationListener(applicationListener);
break;
}
}
}
if (logger.isDebugEnabled()) {
logger.debug(annotatedMethods.size() + " @EventListener methods processed on bean '" +
beanName + "': " + annotatedMethods);
}
}
}
}