死磕Spring系列:Spring事件(Event)传播源码剖析

死磕Spring系列:Spring事件(Event)传播源码剖析,第1张

死磕Spring系列:Spring事件(Event)传播源码剖析 1. 关于事件(Event)通知

什么是事件

event即事件。每一个动作,每一步 *** 作,都可以称之为事件。

事件通知机制的作用

可以将相互耦合的代码解耦,保持功能的单一职责原则。

举个栗子:

注册用户时,需要给用户发送邮箱验证及短信通知。最粗暴的方法就是将邮箱逻辑和短信逻辑内嵌到注册方法中,进行方法调用,如果后续对邮箱和短信逻辑有另外的 *** 作,需要去对原有注册方法进行显示处理。

这样子实现功能和代码结构没什么太大的问题,也比较简单,但是不太利于扩展,对于某些需要扩展性和松耦合的场景不太友好。在这样的场景下,可以将邮箱和短信逻辑从显示调用切换为事件通知的隐式调用,将主要业务代码和扩展的额外代码进行解耦,如果扩展功能有变化,则不需要对原有主体业务进行改动。

2. Spring的Event使用

示例为SpringBoot项目,版本为2.4.5。

  1. 定义一个事件

    package cn.javayuli.event;
    
    import org.springframework.context.ApplicationEvent;
    
    
    public class MyEvent extends ApplicationEvent {
    
        private String msg;
    
        
        public MyEvent(Object source, String msg) {
            super(source);
            this.msg = msg;
        }
    
        public String getMsg() {
            return msg;
        }
    
        public void setMsg(String msg) {
            this.msg = msg;
        }
    }
    
  2. 定义一个事件监听者

    package cn.javayuli.config;
    
    import cn.javayuli.event.MyEvent;
    import org.springframework.context.ApplicationListener;
    import org.springframework.stereotype.Component;
    
    
    @Component
    public class MyEventListener implements ApplicationListener {
        
        @Override
        public void onApplicationEvent(MyEvent event) {
            System.out.println("自定义发布事件");
        }
    }
    
  3. 发布事件

    package cn.javayuli.service;
    
    import cn.javayuli.event.MyEvent;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.ApplicationEventPublisher;
    import org.springframework.stereotype.Service;
    
    
    @Service
    public class MyEventPublisher {
    
        @Autowired
        private ApplicationEventPublisher applicationEventPublisher;
    
        public void publish(String msg) {
            MyEvent myEvent = new MyEvent(this, msg);
            applicationEventPublisher.publishEvent(myEvent);
        }
    }
    
  4. junit测试

    package cn.javayuli.test;
    
    import cn.javayuli.service.MyEventPublisher;
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    
    
    @SpringBootTest
    public class AppTest {
    
        @Autowired
        private MyEventPublisher myEventPublisher;
    
        @Test
        public void testPublish() {
            myEventPublisher.publish("发布了一个自定义事件");
        }
    }
    

3. 流程图 3.1 SpringEvent启动初始化流程

3.2 SpringEvent发送事件流程

4. 源码剖析

从ApplicationEventPublisher类的publishEvent方法切入,ApplicationEventPublisher的实现类有AbstractApplicationContext。其中publishEvent方法的实现代码:

protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
   Assert.notNull(event, "Event must not be null");

   // 如有必要,将事件装饰为ApplicationEvent
   ApplicationEvent applicationEvent;
   if (event instanceof ApplicationEvent) {
      applicationEvent = (ApplicationEvent) event;
   }
   else {
      applicationEvent = new PayloadApplicationEvent<>(this, event);
      if (eventType == null) {
         eventType = ((PayloadApplicationEvent) applicationEvent).getResolvableType();
      }
   }

   // 如果可能,立即传播-或者在传播主机初始化后延迟多播
   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);
      }
   }
}

传播事件multicastEvent方法:

@Override
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)) {
      if (executor != null) {
          // 异步执行listener类中的onApplicationEvent方法
         executor.execute(() -> invokeListener(listener, event));
      }
      else {
          // 同步执行listener类中的onApplicationEvent方法
         invokeListener(listener, event);
      }
   }
}

获取监听类getApplicationListeners方法:

protected Collection> getApplicationListeners(
      ApplicationEvent event, ResolvableType eventType) {

    // new MyEvent时传入的第一个参数,之前传的this,那就是MyEventPublisher类
   Object source = event.getSource();
    // cn.javayuli.service.MyEventPublisher
   Class sourceType = (source != null ? source.getClass() : null);
    // 封装为ListenerCacheKey对象
   ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);

   // Potential new retriever to populate
   CachedListenerRetriever newRetriever = null;

   // Quick check for existing entry on ConcurrentHashMap
   CachedListenerRetriever existingRetriever = this.retrieverCache.get(cacheKey);
   if (existingRetriever == null) {
      // Caching a new ListenerRetriever if possible
      if (this.beanClassLoader == null ||
            (ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
                  (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
         newRetriever = new CachedListenerRetriever();
          // 如果cacheKey在retrieverCache中不存在则将键值对存入且返回newRetriever,否则返回retrieverCache中cacheKey对应的值
         existingRetriever = this.retrieverCache.putIfAbsent(cacheKey, newRetriever);
         if (existingRetriever != null) {
             // 释放newRetriever对象
            newRetriever = null;
         }
      }
   }

   if (existingRetriever != null) {
       // 获取existingRetriever中的ApplicationListener类与其beanName在beanFactory中对应的ApplicationListener bean
      Collection> result = existingRetriever.getApplicationListeners();
      if (result != null) {
         return result;
      }
      // 如果结果为null,则现有检索器(existingRetriever)尚未完全由另一个线程填充。
      // Proceed like caching wasn't possible for this current local attempt.
   }

    // 检索ApplicationListeners
   return retrieveApplicationListeners(eventType, sourceType, newRetriever);
}

检索监听器retrieveApplicationListeners方法:

private Collection> retrieveApplicationListeners(
      ResolvableType eventType, @Nullable Class sourceType, @Nullable CachedListenerRetriever retriever) {
	// 存放所有支持当前事件的监听器
   List> allListeners = new ArrayList<>();
    // 存放所有支持当前事件的的监听器实例
   Set> filteredListeners = (retriever != null ? new linkedHashSet<>() : null);
    // 存放所有支持当前事件的bean名称
   Set filteredListenerBeans = (retriever != null ? new linkedHashSet<>() : null);

   Set> listeners;
   Set listenerBeans;
   synchronized (this.defaultRetriever) {
      listeners = new linkedHashSet<>(this.defaultRetriever.applicationListeners);
      listenerBeans = new linkedHashSet<>(this.defaultRetriever.applicationListenerBeans);
   }

   // Add programmatically registered listeners, including ones coming
   // from ApplicationListenerDetector (singleton beans and inner beans).
   for (ApplicationListener listener : listeners) {
      if (supportsEvent(listener, eventType, sourceType)) {
         if (retriever != null) {
            filteredListeners.add(listener);
         }
         allListeners.add(listener);
      }
   }

   // Add listeners by bean name, potentially overlapping with programmatically
   // registered listeners above - but here potentially with additional metadata.
   if (!listenerBeans.isEmpty()) {
      ConfigurableBeanFactory beanFactory = getBeanFactory();
      for (String listenerBeanName : listenerBeans) {
         try {
            if (supportsEvent(beanFactory, listenerBeanName, eventType)) {
               ApplicationListener listener =
                     beanFactory.getBean(listenerBeanName, ApplicationListener.class);
               if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {
                  if (retriever != null) {
                     if (beanFactory.isSingleton(listenerBeanName)) {
                        filteredListeners.add(listener);
                     }
                     else {
                        filteredListenerBeans.add(listenerBeanName);
                     }
                  }
                  allListeners.add(listener);
               }
            }
            else {
               // Remove non-matching listeners that originally came from
               // ApplicationListenerDetector, possibly ruled out by additional
               // BeanDefinition metadata (e.g. factory method generics) above.
               Object listener = beanFactory.getSingleton(listenerBeanName);
               if (retriever != null) {
                  filteredListeners.remove(listener);
               }
               allListeners.remove(listener);
            }
         }
         catch (NoSuchBeanDefinitionException ex) {
            // Singleton listener instance (without backing bean definition) disappeared -
            // probably in the middle of the destruction phase
         }
      }
   }
    AnnotationAwareOrderComparator.sort(allListeners);
		if (retriever != null) {
			if (filteredListenerBeans.isEmpty()) {
				retriever.applicationListeners = new linkedHashSet<>(allListeners);
				retriever.applicationListenerBeans = filteredListenerBeans;
			}
			else {
				retriever.applicationListeners = filteredListeners;
				retriever.applicationListenerBeans = filteredListenerBeans;
			}
		}
		return allListeners;
	}

这个方法总结起来就是,将所有可支持当前事件的监听器实例放入allListeners,将所有可支持当前事件的监听器实例和单例bean实例放入filteredListeners,将所有可支持当前事件的监听器的多例bean的名称放入filteredListenerBeans。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5438147.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-11
下一篇 2022-12-11

发表评论

登录后才能评论

评论列表(0条)

保存