Spring5源码 - 11 Spring事件监听机制_源码篇

妖狐艹你老母 2022-11-21 03:47 276阅读 0赞

文章目录

  • pre
  • 事件监听机制的实现原理[观察者模式]
    • 事件 ApplicationEvent
    • 事件监听者 ApplicationEvent
    • 事件发布者 ApplicationEventMulticaster (多播器)
  • 工作流程
  • 源码解析
    • 初始化事件多播器 initApplicationEventMulticaster()
    • 注册事件到多播器中 registerListeners()
    • 事件发布publishEvent(默认同步)

在这里插入图片描述


pre

Spring5源码 - 10 Spring事件监听机制_应用篇

观察者模式

说了应用,那我们来看下Spring的源码是如何实现这种事件监听机制的吧


事件监听机制的实现原理[观察者模式]

其实就是观察者模式


事件 ApplicationEvent

事件监听者 ApplicationEvent

相当于观察者模式中的观察者。监听器监听特定事件,并在内部定义了事件发生后的响应逻辑


事件发布者 ApplicationEventMulticaster (多播器)

相当于观察者模式中的被观察者/主题, 负责通知观察者 对外提供发布事件和增删事件监听器的接口,维护事件和事件监听器之间的映射关系,并在事件发生时负责通知相关监听器


工作流程

Spring事件机制是观察者模式的一种实现,但是除了发布者和监听者者两个角色之外,还有一个EventMultiCaster的角色负责把事件转发给监听者。

在这里插入图片描述

AnnotationConfigApplicationContext#publishEvent(ApplicationEvent event)将事件发送给了EventMultiCaster, 而后由EventMultiCaster注册着所有的Listener,然后根据事件类型决定转发给那个Listener。


源码解析

debug走起,

Spring在ApplicationContext接口的抽象实现类AbstractApplicationContext中完成了事件体系的搭建。
AbstractApplicationContext拥有一个applicationEventMulticaster成员变量,applicationEventMulticaster提供了容器监听器的注册表。

在这里插入图片描述

还是进入到refresh方法中

refresh() ——-> 直接看 initApplicationEventMulticaster() —————-> registerListeners() ————-> finishRefresh() 进入 ——> publishEvent(new ContextRefreshedEvent(this))


初始化事件多播器 initApplicationEventMulticaster()

  1. protected void initApplicationEventMulticaster() {
  2. ConfigurableListableBeanFactory beanFactory = getBeanFactory();
  3. //判断IOC容器中包含applicationEventMulticaster 事件多播器的Bean的name
  4. if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
  5. /创建一个applicationEventMulticasterbean放在IOC 容器中,beanname applicationEventMulticaster
  6. this.applicationEventMulticaster =beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
  7. if (logger.isDebugEnabled()) {
  8. logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
  9. }
  10. }
  11. else { //容器中不包含一个beanName 为applicationEventMulticaster的多播器组件
  12. //创建一个SimpleApplicationEventMulticaster 多播器
  13. this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
  14. //注册到容器中
  15. beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
  16. if (logger.isDebugEnabled()) {
  17. logger.debug("Unable to locate ApplicationEventMulticaster with name '" +
  18. APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
  19. "': using default [" + this.applicationEventMulticaster + "]");
  20. }
  21. }
  22. }​

一句话概括:我们可以在配置文件中为容器定义一个自定义的事件广播器,只要实现ApplicationEventMulticaster就可以了,Spring会通过 反射的机制将其注册成容器的事件广播器,如果没有找到配置的外部事件广播器,Spring默认使用 SimpleApplicationEventMulticaster作为事件广播器


注册事件到多播器中 registerListeners()

  1. protected void registerListeners() {
  2. //去容器中把applicationListener 捞取出来注册到多播器上去(系统的)
  3. for (ApplicationListener<?> listener : getApplicationListeners()) {
  4. getApplicationEventMulticaster().addApplicationListener(listener);
  5. }
  6. //开发人员实现了ApplicationListener 的组件
  7. String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
  8. for (String listenerBeanName : listenerBeanNames) {
  9. getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
  10. }
  11. //在这里之前,我们早期想发布的事件 由于没有多播器没有发布,在这里我们总算有了自己的多播器,可以在这里发布早期堆积的事件了. (早起发布事件,会自动发布,无需调用pubilish)
  12. Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
  13. this.earlyApplicationEvents = null;
  14. if (earlyEventsToProcess != null) {
  15. for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
  16. getApplicationEventMulticaster().multicastEvent(earlyEvent);
  17. }
  18. }
  19. }

一句话概括 : Spring根据反射机制,使用ListableBeanFactory的getBeansOfType方法,从BeanDefinitionRegistry中找出所有实现 org.springframework.context.ApplicationListener的Bean,将它们注册为容器的事件监听器,实际的操作就是将其添加到事件广播器所提供的监听器注册表中。


事件发布publishEvent(默认同步)

  1. org.springframework.context.support.AbstractApplicationContext#publishEvent(java.lang.Object, org.springframework.core.ResolvableType)

在这里插入图片描述

进入 org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent(org.springframework.context.ApplicationEvent, org.springframework.core.ResolvableType)

  1. public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
  2. ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
  3. //获取到所有的监听器
  4. for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
  5. //看spring 容器中是否支持线程池 异步发送事件
  6. Executor executor = getTaskExecutor();
  7. if (executor != null) {
  8. executor.execute(new Runnable() {
  9. @Override
  10. public void run() {
  11. invokeListener(listener, event);
  12. }
  13. });
  14. }
  15. else { //同步发送事件
  16. invokeListener(listener, event);
  17. }
  18. }
  19. }

支持异步,默认同步 。

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

在这里插入图片描述

来看看

在这里插入图片描述

  1. private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
  2. try {
  3. //调用对于listener的onApplicationEvent事件
  4. listener.onApplicationEvent(event);
  5. }
  6. catch (ClassCastException ex) {
  7. String msg = ex.getMessage();
  8. if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
  9. // Possibly a lambda-defined listener which we could not resolve the generic event type for
  10. // -> let's suppress the exception and just log a debug message.
  11. Log logger = LogFactory.getLog(getClass());
  12. if (logger.isDebugEnabled()) {
  13. logger.debug("Non-matching event type for listener: " + listener, ex);
  14. }
  15. }
  16. else {
  17. throw ex;
  18. }
  19. }
  20. }

就是调用 listener.onApplicationEvent(event);

在这里插入图片描述


发表评论

表情:
评论列表 (有 0 条评论,276人围观)

还没有评论,来说两句吧...

相关阅读