SpringEvent学习笔记

本文详细阐述了Spring框架中事件的广播过程,包括ApplicationEventMulticaster的作用、事件的同步与异步响应、自定义SimpleApplicationEventMulticaster以及使用@Async进行异步处理的机制。
摘要由CSDN通过智能技术生成

this.earlyApplicationEvents.add(applicationEvent);

}

else {

// 获取ApplicationEventMulticaster,调用multicastEvent方法广播事件

getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);

}

// 如果当前命名空间还有父亲节点,也需要给父亲推送该消息

// Publish event via parent context as well…

if (this.parent != null) {

if (this.parent instanceof AbstractApplicationContext) {

((AbstractApplicationContext) this.parent).publishEvent(event, eventType);

}

else {

this.parent.publishEvent(event);

}

}

}

// 获取ApplicationEventMulticaster

ApplicationEventMulticaster getApplicationEventMulticaster() throws IllegalStateException {

if (this.applicationEventMulticaster == null) {

throw new IllegalStateException("ApplicationEventMulticaster not initialized - " +

"call ‘refresh’ before multicasting events via the context: " + this);

}

return this.applicationEventMulticaster;

}

经过上面的分析,我们看到事件是通过applicationEventMulticaster来广播出去的。

applicationEventMulticaster在Spring的启动过程中被建立,我们在之前的文章Spring启动过程分析1(overview)中分析过Spring的启动过程,在核心方法refresh中建立applicationEventMulticaster:

// Initialize message source for this context.

initMessageSource();

// Initialize event multicaster for this context.

// 在Spring容器中初始化事件广播器,事件广播器用于事件的发布

initApplicationEventMulticaster();

// Initialize other special beans in specific context subclasses.

onRefresh();

// Check for listener beans and register them.

// 把Spring容器内的事件监听器和BeanFactory中的事件监听器都添加的事件广播器中。

registerListeners();

// Instantiate all remaining (non-lazy-init) singletons.

finishBeanFactoryInitialization(beanFactory);

// Last step: publish corresponding event.

finishRefresh();

关注initApplicationEventMulticaster和registerListeners方法。

// 初始化事件广播器

protected void initApplicationEventMulticaster() {

ConfigurableListableBeanFactory beanFactory = getBeanFactory();

// 如果用户手动新建了一个名为applicationEventMulticaster类型为ApplicationEventMulticaster的bean,则将这个bean作为事件广播器

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 {

// 否则新建一个SimpleApplicationEventMulticaster作为默认的事件广播器

this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);

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() + “]”);

}

}

}

// 注册监听器

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!

// 获取类型是ApplicationListener的beanName集合,此处不会去实例化bean

String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);

for (String listenerBeanName : listenerBeanNames) {

getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);

}

// Publish early application events now that we finally have a multicaster…

Set earlyEventsToProcess = this.earlyApplicationEvents;

this.earlyApplicationEvents = null;

// 如果存在earlyEventsToProcess,提前处理这些事件

if (earlyEventsToProcess != null) {

for (ApplicationEvent earlyEvent : earlyEventsToProcess) {

getApplicationEventMulticaster().multicastEvent(earlyEvent);

}

}

}

经过前面的分析,我们知道了事件广播器applicationEventMulticaster如何被构建,下面我们分析事件的广播过程

@Override

public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {

ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));

// 根据event类型获取适合的监听器

for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {

// 获取SimpleApplicationEventMulticaster中的线程执行器,如果存在线程执行器则在新线程中异步执行,否则直接同步执行监听器中的方法

Executor executor = getTaskExecutor();

if (executor != null) {

executor.execute(() -> invokeListener(listener, event));

}

else {

invokeListener(listener, event);

}

}

}

protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {

// 如果存在ErrorHandler,调用监听器方法如果抛出异常则调用ErrorHandler来处理异常。否则直接调用监听器方法

ErrorHandler errorHandler = getErrorHandler();

if (errorHandler != null) {

try {

doInvokeListener(listener, event);

}

catch (Throwable err) {

errorHandler.handleError(err);

}

}

else {

doInvokeListener(listener, event);

}

}

异步响应Event

默认情况下,Spring是同步执行Event的响应方法的。如果响应方法的执行时间很长会阻塞发送事件的方法,因此很多场景下,我们需要让事件的响应异步化。

为了更直观地说明Event的响应默认是同步的,我们修改一下EventDemoListener并增加一个EventDemoListener2:

@Component

public class EventDemoListener1 implements ApplicationListener{

Logger logger = LoggerFactory.getLogger(EventDemoListener1.class);

@Override

public void onApplicationEvent(EventDemoVO eventDemoVO) {

logger.info("receiver 1 " + eventDemoVO.getMessage());

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

@Component

public class EventDemoListener2 implements ApplicationListener {

Logger logger = LoggerFactory.getLogger(EventDemoListener2.class);

@Override

public void onApplicationEvent(EventDemoVO eventDemoVO) {

logger.info("receiver 2 " + eventDemoVO.getMessage());

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

执行结果如下:

在这里插入图片描述

执行结果显示:EventDemoListener2和EventDemoListener1和EventDemoListener的执行间隔1秒,EventDemoListener2的执行和程序的结束也间隔1秒。结果表示我们的响应程序是同步执行的,一个响应程序的执行会阻塞下一个响应程序的执行。

自定义SimpleApplicationEventMulticaster

通过前面的代码分析,我们发现如果SimpleApplicationEventMulticaster中的taskExecutor如果不为null,将在taskExecutor中异步执行响应程序。applicationEventMulticaster的新建在initApplicationEventMulticaster方法中,默认情况下它会新建一个SimpleApplicationEventMulticaster,其中的taskExecutor为null。因此想要taskExecutor不为null,我们可以自己手动创建一个SimpleApplicationEventMulticaster然后设置一个taskExecutor。

@Configuration

@ComponentScan(“com.springevent”)

public class ListenerConfig {

@Bean

public SimpleAsyncTaskExecutor simpleAsyncTaskExecutor(){

return new SimpleAsyncTaskExecutor();

}

/**

  • 手动设置一个taskExecutor

  • */

@Bean

public SimpleApplicationEventMulticaster applicationEventMulticaster(){

SimpleApplicationEventMulticaster simpleApplicationEventMulticaster=new SimpleApplicationEventMulticaster();

simpleApplicationEventMulticaster.setTaskExecutor(simpleAsyncTaskExecutor());

return simpleApplicationEventMulticaster;

}

}

@Async

前面我们看到,通过手动新建SimpleApplicationEventMulticaster并设置TaskExecutor可以使所有的事件响应程序都在另外的线程中执行,不阻塞主程序的执行。不过这样也带来一个问题,那就是所有的事件响应程序都异步化了,某些场景下我们希望某些关系密切的响应程序可以同步执行另外一些响应程序异步执行。这种场景下,我们就不能简单地新建SimpleApplicationEventMulticaster并设置TaskExecutor。

Spring中提供了一个@Async注解,可以将加上这个注解的方法在另外的线程中执行。通过这个注解我们可以将指定的事件响应程序异步化。

我们修改EventDemoListener,在onApplicationEvent中加上@Async注解;同时修改Config类:

@Configuration

@ComponentScan(“com.springevent”)

@EnableAsync

public class AsyncConfig {

@Bean

public SimpleAsyncTaskExecutor simpleAsyncTaskExecutor(){

return new SimpleAsyncTaskExecutor();

}

}

@Component

public class EventDemoListener1 implements ApplicationListener{

Logger logger = LoggerFactory.getLogger(EventDemoListener1.class);

// @Override

// public void onApplicationEvent(EventDemoVO eventDemoVO) {

// logger.info("receiver 1 " + eventDemoVO.getMessage());

// try {

// Thread.sleep(1000);

// } catch (InterruptedException e) {

// e.printStackTrace();

// }

// }

@Override

@Async

public void onApplicationEvent(EventDemoVO eventDemoVO) {

logger.info("receiver 1 " + eventDemoVO.getMessage());

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

@Component

public class EventDemoListener2 implements ApplicationListener {

最后

分享一些资料给大家,我觉得这些都是很有用的东西,大家也可以跟着来学习,查漏补缺。

《Java高级面试》

《Java高级架构知识》

《算法知识》

onApplicationEvent(EventDemoVO eventDemoVO) {

logger.info("receiver 1 " + eventDemoVO.getMessage());

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

@Component

public class EventDemoListener2 implements ApplicationListener {

最后

分享一些资料给大家,我觉得这些都是很有用的东西,大家也可以跟着来学习,查漏补缺。

《Java高级面试》

[外链图片转存中…(img-RLQsWF26-1714469430479)]

《Java高级架构知识》

[外链图片转存中…(img-Esv7JvLD-1714469430480)]

《算法知识》

[外链图片转存中…(img-QOPstSvg-1714469430480)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值