天天看點

Spring Event 源碼 (四) (事件以及監聽器的源碼解析)

文章目錄

  • ​​1.執行個體代碼​​
  • ​​2.源碼分析​​
  • ​​2.1 添加後置處理器源碼解析​​
  • ​​2.2 發送事件源碼分析​​
  • ​​3.總結​​

1.執行個體代碼

Spring Event 源碼 (四) (事件以及監聽器的源碼解析)
@Configuration
@ComponentScan("com.atguigu.event")
public class EventConfig {
}      

監聽器

@Component
public class MyApplicationListener implements ApplicationListener<ApplicationEvent> {
    // 監聽器如何感覺到事件的:
    // ApplicationEvent 和 Payload
    // getApplicationEventMulticaster: 獲得多點傳播器, 發送事件
    // 觀察者模式: 将所有的事件監聽器拿到, 矮個周遊, 調用onApplicationEvent()方法

    // 事件派發: 周遊監聽器, 調用onApplicationEvent()方法
    // 釋出事件觸發
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        System.out.println(event);
    }
}      

服務代碼

@Component
public class UserService {
    // EventListenerMethodProcessor, DefaultEventListenerFactory
    // 後置處理和初始化
    // SmartInitializingSingleton: 工廠後置處理環節, 執行增強和所有Bean完全建立好後執行初始化
    // 後置增強環節: EventListenerMethodProcessor.postProcessBeanFactory(): 拿到所有的EventListenerFactory, 排序
    // 初始化環節: afterSingletonsInstantiated():拿到容器中所有的元件, 處理這個元件
    // 1.找到@EventListener 方法
    // 2.周遊每一個方法: 拿到DefaultEventListenerFactory, 目前方法, beanName 封裝到擴充卡中ApplicationListenerMethodAdapter
    // 工廠的作用為創造擴充卡: 擴充卡是一個監聽器, 多點傳播器注冊監聽器, 容器注冊監聽器, 事件派發給的是擴充卡, 擴充卡反射調用元件的事件監聽方法
    // 标了@EventListener 注解, 就建立擴充卡, 擴充卡反射調用方法
    // EventListenerMethodProcessor這個後置處理器為每一個監聽方法建立一個監聽器元件(擴充卡)

    // 釋出器和監聽器
    // 感覺的對象
    @EventListener(classes = ApplicationEvent.class)
    public void listener(ApplicationEvent event){
        System.out.println("UserService : " + event);

    }
}      

主類

public class MainApplication {
    public static void main(String[] args) {
        /**
         * 事件的釋出和監聽機制的原理:
         * 擷取到EventMulticaster: 事件派發器
         * 事件派發器: getApplicationEventMulticaster(): refresh(): initApplicationEventMulticaster()
         * 容器中有哪些監聽器: refresh(): registerListener()
         *
         * @EventListener:
         * EventListenerMethodProcessor->SmartInitializingSingleton, 單執行個體Bean建立完成後執行
         */
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(EventConfig.class);
        // 釋出事件
        context.publishEvent(new ApplicationEvent("1") {
        });
        context.close();
        // ContextRefreshedEvent,source,ContextClosedEvent
    }
}      

釋出事件

Spring Event 源碼 (四) (事件以及監聽器的源碼解析)

2.源碼分析

  • 建立過程
  • 運作過程

2.1 添加後置處理器源碼解析

添加後置處理器為建立過程

在ioc容器啟動(this()方法)的時候, 會加載EventListenerMethodProcessor 這個工廠後置處理器

Spring Event 源碼 (四) (事件以及監聽器的源碼解析)

這個後置處理器實作了​

​SmartInitializingSingleton​

​​和 ​

​BeanFactoryPostProcessor​

​ 兩個接口

​SmartInitializingSingleton​

​: 工廠後置處理環節, 執行增強和所有Bean完全建立好後執行初始化

  • 後置增強環節: EventListenerMethodProcessor.postProcessBeanFactory(): 拿到所有的EventListenerFactory, 并排序
  • 初始化環節: afterSingletonsInstantiated():拿到容器中所有的元件, 處理這個元件
Spring Event 源碼 (四) (事件以及監聽器的源碼解析)

postProcessBeanFactory: 拿到所有的EventListenerFactory, 并進行排序

Spring Event 源碼 (四) (事件以及監聽器的源碼解析)

afterSingletonsInstantiated: 拿到容器中所有的元件, 處理這個元件

Spring Event 源碼 (四) (事件以及監聽器的源碼解析)

​processBean()​

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 {
        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 {
        // 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");
        for (Method method : annotatedMethods.keySet()) {
          for (EventListenerFactory factory : factories) {
            if (factory.supportsMethod(method)) {
              Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));
              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);
        }
      }
    }
  }      

拿到​

​DefaultEventListenerFactory​

​, 然後封裝進擴充卡中

Spring Event 源碼 (四) (事件以及監聽器的源碼解析)
  1. 找到@EventListener 方法
  2. 周遊每一個方法: 拿到DefaultEventListenerFactory, 目前方法, beanName 封裝到擴充卡中ApplicationListenerMethodAdapter
  3. 工廠的作用為創造擴充卡: 擴充卡是一個監聽器, 多點傳播器注冊監聽器, 容器注冊監聽器, 事件派發給的是擴充卡, 擴充卡反射調用元件的事件監聽方法。

    标了@EventListener 注解, 就建立擴充卡, 擴充卡反射調用方法。

EventListenerMethodProcessor這個後置處理器為每一個監聽方法建立一個監聽器元件(擴充卡)

2.2 發送事件源碼分析

發送事件過程為運作事件過程

Spring Event 源碼 (四) (事件以及監聽器的源碼解析)
Spring Event 源碼 (四) (事件以及監聽器的源碼解析)
Spring Event 源碼 (四) (事件以及監聽器的源碼解析)

觀察者模式: for 循環

Spring Event 源碼 (四) (事件以及監聽器的源碼解析)
Spring Event 源碼 (四) (事件以及監聽器的源碼解析)

調用每一個監聽器的​

​onApplicationEvent​

​方法

3.總結

繼續閱讀