Spring中事件监听处理流程全解析

上一篇文章深入理解事件发布监听机制,小编实现了一个基于jdk的事件监听处理的小程序,虽然功能简单,但是却很详细的说明了事件监听处理的原理。在Spring中也有完整的事件监听处理机制,原理和jdk的事件处理流程大概是相同的,只不过Spring在实现的过程中,有一些特殊的细节处理。比如:事件类型和监听器对应关系的缓存,事件处理的异步化,异常处理器定义。

下面我们基于Spring中的事件处理机制实现一个和上篇文章相同的事件监听处理程序,然后,从源码角度看一下Spring是如何实现事件监听处理机制的。

案例解析

为了更直观的了解Spring的事件监听处理机制,我们先基于Spring重新实现上篇文章中的任务状态变更事件的监听处理应用。

定义事件
public class TaskInitEvent extends ApplicationEvent {

    public TaskInitEvent(Object source) {
        super(source);
    }

    @Override
    public String toString() {
        return "TaskInitEvent{" +
                "source=" + source +
                '}';
    }
}

在spring中,定义的事件要继承 ApplicationEvent,其实ApplicationEvent同样继承了 EventObject只不过扩展了一个 timestamp时间戳字段。

这里只为了说明spring事件处理的原理,对于另外两个事件 TaskProcessEvent,TaskFinishEvent暂不做详细定义。

定义事件监听器
@Component
public class TaskInitEventListener implements ApplicationListener<TaskInitEvent> {

    @Override
    public void onApplicationEvent(TaskInitEvent event) {
        System.out.println("处理初始化事件: "+ event.toString());
    }
}

在spring中自定义的事件监听器,要实现ApplicationListener接口,而ApplicationListener继承了EventListener接口,也就是说,Spring中的事件监听处理机制的实现也是遵从jdk中事件处理规范的。

定义事件发布器

在sprig中我们无需定义事件发布器,ApplicationContext具备发布事件的能力,可以将ApplicationContext作为事件发布器即可。事件发布程序如下:

@SpringBootApplication
public class SpringEventApp {

    public static void main(String[] args) {
        ApplicationContext applicationContext = SpringApplication.run(SpringEventApp.class, args);
        Task initTask = new Task("init");
        TaskInitEvent initEvent = new TaskInitEvent(initTask);
        applicationContext.publishEvent(initEvent);
    }
} 

在控制台可以看到如下图的输出:
在这里插入图片描述

源码解析

我们都知道事件处理主要有三个组件构成:事件发送器,事件定义,事件监听器。
接下来,我们就Spring源码,看一下这三个组件是如何加载,以及如何根据事件找到对应的监听器,进而完成事件处理的。

在看源码前,我这里先提出几个问题,带着问题看代码才能更有目的性:

1.ApplicationConext为什么具有事件发布的能力,可以发布事件?

2.事件监听器是如何加载?

3.发布的事件是如何找到对应的事件监听器的?

publisher如何加载的

上面说ApplicationContext具有事件发布的能力,其实事件并不是ApplicationContext,真正的事件发布器是ApplicationEventMulticaster发布的。它定义在AbstractApplicationContext中,并在ApplicationContext容器启动的时候进行初始化。具体的初始化逻辑,就定义在大名鼎鼎的refrsh()方法中:

public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			prepareBeanFactory(beanFactory);
			try {
				...
				// 初始化事件发布器.
				initApplicationEventMulticaster();
				...
				//注册事件监听器.
				registerListeners();
				...
			}

			catch (BeansException ex) {
				...
			}

			finally {
				...
			}
		}
	}

而在 initApplicationEventMulticaster
方法中完成了 applicationEventMulticaster的初始化,具体如下:

protected void initApplicationEventMulticaster() {
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
			this.applicationEventMulticaster =
					beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
			if (logger.isDebugEnabled()) {
				logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
			}
		}
		else {
			this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
			beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
			if (logger.isDebugEnabled()) {
				logger.debug("Unable to locate ApplicationEventMulticaster with name '" +
						APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
						"': using default [" + this.applicationEventMulticaster + "]");
			}
		}
	}

这里会根据核心容器beanFactory中是否有id为applicationEventMulticaster的bean分两种情况:

1.容器中已有id为applicationEventMulticaster的bean直接从容器缓存获取或是创建该bean实例,并交由成员变量applicationEventMulticaster保存。当用户自定义了事件发布器并向容器注册时会执行该流程。

2.容器中不存在applicationEventMulticaster的bean这是容器默认的执行流程,会创建一个SimpleApplicationEventMulticaster。

到这里完成了事件发布器的初始化,我们知道事件监听处理机制是一种观察者模式的应用,事件发布器会持有所有的事件监听器的实例,那么这些监听器的实例从哪里注册进去的呢?

listener是如何加载的

注册事件监听器的流程,同样在spring的IOC的refresh方法中,具体代码如下:



public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
		// 向beanFactory中添加 BeanPostProcesser ApplicationListenerDetector,这个BeanPostProcessor将实现ApplicationListener的bean进行注册。
			prepareBeanFactory(beanFactory);
			try {
				...
				// 初始化事件发布器.
				initApplicationEventMulticaster();
				...
				//注册事件监听器.
				registerListeners();
				...
			}

			catch (BeansException ex) {
				...
			}

			finally {
				...
			}
		}
	}

其中BeanPostProcessor ApplicationListenerDetector会将所有ApplicationListener的bean添加到 AbstractApplicationContext的 applicationListeners 集合中,具体代码如下:

public Object postProcessAfterInitialization(Object bean, String beanName) {
		//过滤 ApplicationListener
		if (bean instanceof ApplicationListener) {
			Boolean flag = this.singletonNames.get(beanName);
			if (Boolean.TRUE.equals(flag)) {
				// 将ApplicationListener添加到 AbstractApplicationContext的 applicationListeners 中
			this.applicationContext.addApplicationListener((ApplicationListener<?>) bean);
			}
			else if (Boolean.FALSE.equals(flag)) {
				...
		}
		return bean;
	}

同时方法registerListeners会将AbstractApplicationContext中的 applicationListeners 注册到 ListenerRetriever的 applicationListeners集合中,完成listener的注册,具体注册逻辑如下:

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 listenerBeanName : listenerBeanNames) {
			getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
		}

		// Publish early application events now that we finally have a multicaster...
		Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
		this.earlyApplicationEvents = null;
		if (earlyEventsToProcess != null) {
			for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
				getApplicationEventMulticaster().multicastEvent(earlyEvent);
			}
		}
	}

到这里完成了 事件监听器的注册。

现在有了事件发布器和事件监听器,接下来,我们就来研究下,事件发布器是如何将事件发布出去的,以及对应的事件监听器是如何处理被发布的事件。

event是如何处理的

事件发布的主要流程如下(为了更加清晰的理解事件发布的流程,这里只展示一些关键路径的上的代码) 首先AbstractApplicationContext的publishEvent方法,是事件发布的入口:

public void publishEvent(ApplicationEvent event) {
		publishEvent(event, null);
	}

publishEvent方法具体如下:

protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
		...

		// Multicast right now if possible - or lazily once the multicaster is initialized
		if (this.earlyApplicationEvents != null) {
			this.earlyApplicationEvents.add(applicationEvent);
		}
		else {
		// 发布事件
			getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
		}

		...
	}

在调用 multicastEvent方法时,会将事件的类型作为入参:

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);
			}
		}
	}

调用resolveDefaultEventType(event)方法,获取事件的事件类型信息,通过getApplicationListeners(event, type)方法得到所有和该事件类型匹配的事件监听器,对于如何找到和事件匹配的listeners,读者可以自行参考 AbstractApplicationEventMulticaster中的方法:

protected boolean supportsEvent(
			ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType)

对于匹配的每一个监听器,视事件发布器内是否设置了任务执行器实例Executor,决定以何种方式对监听器的监听方法进行回调。

若执行器实例Executor未设置,则进行同步回调,即在当前线程执行监听器的回调方法
若用户设置了Executor实例(通常而言是线程池),则会进行异步回调,监听器的监听方法会交由线程池中的线程去执行。

到这里事件的发布和处理的流程就说完了。

自定义事件发送器

上面说有说Spring的 SimpleApplicationEventMulticaster是支持异步事件处理的,但是默认情况只支持同步的处理,因为Spring在初始化 SimpleApplicationEventMulticaster时,并没有对属性 taskExecutor和errorHandler进行初始化。如果我们想要实现事件处理异步化和自定义异常处理的化,可以通过自定义事件发布器实现;

@Configuration
public class AsyncTaskConfig {
    public SimpleAsyncTaskExecutor simpleAsyncTaskExecutor() {
        return new SimpleAsyncTaskExecutor();
    }

    public ErrorHandler errorHandler(){
        return new ErrorHandler() {
            @Override
            public void handleError(Throwable t) {
                System.err.println("事件监听器出错:"+t.getMessage());
            }
        };
    }
 
    @Bean
    public SimpleApplicationEventMulticaster applicationEventMultica1ster() {
        SimpleApplicationEventMulticaster simpleApplicationEventMulticaster = new SimpleApplicationEventMulticaster();
        simpleApplicationEventMulticaster.setTaskExecutor(simpleAsyncTaskExecutor());
        simpleApplicationEventMulticaster.setErrorHandler(errorHandler());
        return simpleApplicationEventMulticaster;
    }
}

通过修改Listener的事件处理逻辑,让事件处理抛出异常,对ErrorHander进行验证,并打印出事件处理逻辑所在的线程名称:

@Component
public class TaskInitEventListener implements ApplicationListener<TaskInitEvent> {

    @Override
    public void onApplicationEvent(TaskInitEvent event) {
        System.out.println("处理初始化事件: "+ event.toString()+" thread name:"+Thread.currentThread().getName());
    }
}

执行结果如下图:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值