4 Spring源碼 --- 監聽器的原理


目標:

1. 監聽器如何使用

2. 監聽器的原理

3. 監聽器的類型

4. 多播器的概念和作用

5. 接口類型的監聽器是如何注冊的?

6. 注解類型的監聽器和如何注冊的?

7. 如果想在所有的bean都加載完成以后做一些事情, 怎么辦?


 

 一. 監聽器的使用

為什么要學習監聽器呢?學習監聽器主要學習監聽器的設計思想。 比如,我們之前研究過的nacos,他就是使用監聽器進行集成的。所以了解監聽器的原理,就很重要了。

首先, 我們要知道監聽器如何使用。 

1.1 Spring事件的原理

原理: 是觀察者模式

Spring的事件監聽有三個組成部分:

1. 事件(ApplicationEvent):要廣播,發送的消息. 監聽器監聽的事情
2. 監聽器(ApplicationListener): 觀察者模式中的觀察者, 監聽器監聽特定事件, 並在內部定義了事件發生后的相應邏輯.
3. 事件發布器(ApplicationEventMulticaster):對應於觀察者模式中的被觀察者/主題.負責通知觀察者. 對外提供發布事件和增刪事件監聽器的接口.維護事件和事件監聽器之間的關系.並在事件發生時負責通知事件監聽器.

 

1.2 認識監聽器

上面認識了監聽器. 接下來看一個例子. 通過例子來理解.

就好比現在有一個消息, 比如說: 下單后減庫存. 減庫存就是一個事件, 這個事件需要一個事件播放器, 將事件播放出去. 然后另一端事件監聽器, 接收到信息,進行處理.

比如:下面的demo

有一個訂單Order :

package com.lxl.www.events;

/**
 * Description
 *
 * DATE 2020/11/17.
 *
 * @author lxl.
 */
public class Order {
    private Integer id;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }
}

接下來, 有一個訂單事件. 訂單的操作,帶來的庫存的增減. 就是一個訂單事件

package com.lxl.www.events;

import org.springframework.context.ApplicationEvent;

import java.io.Serializable;

/**
 * Description
 * 訂單的事件
 *
 * 事件的分類: 分為自定義事件和內置事件
 * DATE 2020/11/17.
 *
 * @author lxl.
 */
public class OrderEvent  extends ApplicationEvent implements Serializable {

    private static final long serialVersionUID = 1L;

    private String name;
    public OrderEvent(Object event, String name) {
        super(event);
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

第三: 事件監聽器 ,事件監聽器用來監聽事件. 當OrderEvent發布減庫存消息的時候, 事件監聽器就能聽到.

package com.lxl.www.events;

import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

/**
 * Description
 * OrderEvent的事件監聽器
 *
 *
 * DATE 2020/11/17.
 *
 * @author lxl.
 */
@Component
public class OrderEventListenter implements ApplicationListener<OrderEvent> {
    /**
     * 當某一個事件發布的時候, 就會觸發事件監聽器
     * @param event the event to respond to
     */
    @Override
    public void onApplicationEvent(OrderEvent event) {
        if (event.getName().equals("減庫存")) {
            System.out.println("事件監聽器  監聽到  減庫存");
        }
    }
}

是不是和mq相差不多.

mq也是一個訂閱者,一個發布者. 

下面寫一個main方法, 運行看看監聽器的效果

package com.lxl.www.events;

import org.springframework.beans.factory.parsing.SourceExtractor;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 *  監聽器的使用
 */
public class MainClass {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MainConfig.class);

        /**
         * 使用場景: 比如有一個訂單, 由用戶下單了,那么對應的就要減庫存.其實下單和減庫存不需要是串行.
         * 通常, 我們會使用一個mq去處理減庫存的情況. 也就是采用異步的方式.
         *
         * 那么, 監聽器的遠離和mq是類似的. 我們可以手動設置采用同步還是異步的方式處理.
         */
        Order order = new Order();
        order.setId(1);
        System.out.println("下單");

        // 發布事件. 當在這里發布事件, 那么就會被事件監聽器監聽到
        ctx.publishEvent(new OrderEvent(order, "減庫存"));
        System.out.println("日志.....");
    }
}

輸出結果

下單
事件監聽器  監聽到  減庫存
日志.....

監聽器使用的設計模式是: 觀察者模式.

 

1.3 監聽器的類型

監聽器有兩種類型: 一種是內置的監聽器, 一種是自定義監聽器. 

1.3.1 內置監聽器

 spring設置了一個內置監聽器的父類.

public abstract class ApplicationContextEvent extends ApplicationEvent {

    /**
     * Create a new ContextStartedEvent.
     * @param source the {@code ApplicationContext} that the event is raised for
     * (must not be {@code null})
     */
    public ApplicationContextEvent(ApplicationContext source) {
        super(source);
    }

    /**
     * Get the {@code ApplicationContext} that the event was raised for.
     */
    public final ApplicationContext getApplicationContext() {
        return (ApplicationContext) getSource();
    }

}

實現了ApplicationContextEvent的類就是內置的監聽器. 我們使用快捷鍵ctrl + H, 查看都有哪些類實現了 ApplicationContextEvent

 

一共有5各類實現了ApplicationContextEvent.  

Event  說明
ContextRefreshEvent

當容器被實例化或者refresh時發布.如調用refresh()方法. 此處的實例化是指所有的bean都已被加載,后置處理器都被激活,所有單例bean都已被實例化,所有的容器對象

都已經准備好可使用. 如果容器支持熱重載,則refresh()可以被觸發多次(XmlWebApplicationContext支持熱刷新, 而GenericApplicationContext不支持熱刷新)

ContextStartedEvent 當容器啟動時發布, 即調用start()方法, 已啟用意味着所有的lifecycle都已顯示收到了start的信號
ContextStoppedEvent 當容器停止時發布. 即調用stop()方法, 既所有的lifecycle bean都已顯示接收了stop信號, 關閉的容器可以通過start()方法重啟
ContextClosedEvent 當容器關閉時發布. 即調用close()方法, 關閉意味着所有的單例bean都已被銷毀. 關閉的容器不能被重啟或refresh()

 

 1. ContextRefreshEvent: 當容器被實例化或者refresh時發布

我們來看看一下源碼.

從refresh()源碼進入.

public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
        // 進入構造函數, 首先調用自身的構造方法this();
        // 調用自身的構造方法之前, 要先調用父類的構造方法
        this();
        // register配置注冊類
        register(componentClasses);
        // ioc容器刷新接口--非常重要  refresh();
    }
/**
     * refresh是spring最核心的方法, 里面包含了整個spring ioc的全過程, 包括spring加載bean到銷毀bean的全過程
     * 學習spring, 就是學習里面的13個方法, 如果13個方法都學完了, 基本上就打通了
     * @throws BeansException
     * @throws IllegalStateException
     */
    @Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // 1. 准備刷新上下文環境
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
            //2. 獲取告訴子類初始化bean工廠, 不同工廠不同實現
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        ......
// Last step: publish corresponding event.
                //最后容器刷新 發布刷新時間(spring cloud是從這里啟動的 )  finishRefresh();
            }
      
      ......

    }
    }

進入到finishRefresh()方法

protected void finishRefresh() {
        // Clear context-level resource caches (such as ASM metadata from scanning).
        // 清除上下文緩存
        clearResourceCaches();

        // Initialize lifecycle processor for this context.
        // 注冊lifecycleProcessor聲明周期處理器
        // 作用: 當ApplicationContext啟動或停止時, 他會通過LifecycleProcessor來與所有聲明的bean進行交互
        initLifecycleProcessor();

        // Propagate refresh to lifecycle processor first.
        // 為實現了SmartLifeCycle並且isAutoStartup, 自動啟動的Lifecycle調用start()方法
        getLifecycleProcessor().onRefresh();
    // 發布容器啟動完畢事件 publishEvent(new ContextRefreshedEvent(this)); // Participate in LiveBeansView MBean, if active.
        LiveBeansView.registerApplicationContext(this);
    }

我們看到有一個發布事件. 這個事件的作用是通知容器已經啟動完畢. 注意看, 里面發布的是什么事件? new ContextRefreshedEvent(this). 發布的是ContextRefreshedEvent事件.

下面有一個問題:  怎么樣可以在所有的bean創建完以后做擴展代碼呢?

上面我們說到了, 當所有的bean都創建完以后, 會調用publishEvent(new ContextRefreshedEvent(this));發布容器啟動完畢的事件.

這時我們可以自定義一個監聽器, 用來監聽ContextRefreshedEvent事件.

/**
 * 自定義一個事件監聽器, 用來監聽ContextRefreshedEvent事件
 */
@Component
public class ContextRefreshedEventListener {

  /**
   * 聲明這是一個事件監聽器, 監聽的是ContextRefreshedEvent事件.
   * @param event
   */
  @EventListener(ContextRefreshedEvent.class)
  public void onApplicationEvent(ContextRefreshedEvent event) {
      ....
    // 在所有的bean創建完以后, 寫一些邏輯代碼

  }
}

然后, 在里面寫上我們需要在容器都創建完畢之后執行的邏輯代碼.

 

2. ContextClosedEvent: 當容器關閉時發布

還是先來看源碼, spring是在何時發布的這個事件.

protected void doClose() {
        // Check whether an actual close attempt is necessary...
        if (this.active.get() && this.closed.compareAndSet(false, true)) {
            if (logger.isDebugEnabled()) {
                logger.debug("Closing " + this);
            }

            LiveBeansView.unregisterApplicationContext(this);

            try {
                // Publish shutdown event. publishEvent(new ContextClosedEvent(this));
            }
            catch (Throwable ex) {
                logger.warn("Exception thrown from ApplicationListener handling ContextClosedEvent", ex);
            }

            // Stop all Lifecycle beans, to avoid delays during individual destruction.
            if (this.lifecycleProcessor != null) {
                try {
                    this.lifecycleProcessor.onClose();
                }
                catch (Throwable ex) {
                    logger.warn("Exception thrown from LifecycleProcessor on context close", ex);
                }
            }

            // Destroy all cached singletons in the context's BeanFactory.
            destroyBeans();

            // Close the state of this context itself.
            closeBeanFactory();

            // Let subclasses do some final clean-up if they wish...
            onClose();

            // Reset local application listeners to pre-refresh state.
            if (this.earlyApplicationListeners != null) {
                this.applicationListeners.clear();
                this.applicationListeners.addAll(this.earlyApplicationListeners);
            }

            // Switch to inactive.
            this.active.set(false);
        }
    }

在doClose()的時候, 發布了publishEvent(new ContextClosedEvent(this));事件

我們看一看具體發布的是什么事件呢? 就是ContextClosedEvent事件

假如: 我們想要在容器關閉的時候做一些擴展, 就可以寫一個監聽器, 在容器關閉的時候監聽ContextClosedEvent事件

  

 Spring內置的事件, 我們就不用再自己定義了. 我們需要做的就是定義一個監聽器, 監聽事件就可以了.

 

 1.3.2 自定義監聽器

不是spring定義的監聽器, 也就是我們自己定義的監聽器就是自定義監聽器. 下面來看看自定義監聽器的兩種類型. 

類型一: 基於接口 

@Component
public class HelloEventListener implements ApplicationListener<OrderEvent> {

  @Override
  public void onApplicationEvent(OrderEvent event) {
      if (event.getName().equals("減庫存")) {
        System.out.println("減庫存....");
      }
  }
}

事件監聽器需要實現ApplicationListener接口, 這是一個泛型接口, 泛型的類型就是事件的類型.

其次, 這個監聽器需要是spring容器托管的bean, 因此加上了@Component注解, 里面只有一個方法onApplicationEvent, 就是事件觸發時執行的內容. 

類型二: 基於注解

@Component
public class OrderEventListener {

  @EventListener(OrderEvent.class) public void onApplicationEvent(OrderEvent event) {
    if (event.getName().equals("減庫存")) {
      System.out.println("減庫存....");
    }
  }

在方法上面添加注解@EventListener(OrderEvent.class) 監聽的是哪個事件呢?OrderEvent.class

 我們在定義監聽器的時候, 可以選擇是基於接口的方式還是基於注解的方式.

 二. 監聽器源碼

 首先, 監聽器的聲明,調用,都是在refresh()方法里面進行,我們先來看看refresh()的整體脈絡. 其中標紅的部分是和監聽器有關系的模塊.

 

 這里面的第五步, 第九步, 第十一步, 都詳細的分析過. 下面主要看看和監聽器有關的幾步.

 2.1 准備上下文環境prepareRefresh()

在准備上下文環境的時候, 我們看看做了哪些事情

 

 1. 設置了容器當期的狀態, 是激活狀態

2. 初始化了屬性源initPropertySources();.

在AbstractApplicationContext類中沒有實現這個方法. 這是一個父類定義的方法. 比如:我們可以自定義一個類, 然后重寫initPropertySource, 在改方法中設置一個環境變量abc, 那么在容器啟動的時候, 就會去環境變量中檢查, 是否環境變量中有這個屬性, 如果沒有就會拋出異常.

3. 接下來就是驗證上面環境變量中指定的屬性是否存在了. getEnvironment().validateRequiredProperties(); 不存在就拋出異常MissingRequiredPropertiesException

4. 然后接下來,和事件有關的一步, 創建了早期的事件監聽器

     // 創建早期的事件監聽器.
        // Store pre-refresh ApplicationListeners...
        if (this.earlyApplicationListeners == null) {
            this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
        }
        else {
            // Reset local application listeners to pre-refresh state.
            this.applicationListeners.clear();
            this.applicationListeners.addAll(this.earlyApplicationListeners);
        }

這里有一個問題, 什么是早期的事件監聽器呢? 早對應的就是晚了. 早期指的是多早呢?

早期事件指的是事件監聽器還沒有注冊到事件多播器的時候.

早期定義的事件不需要手動的publishEvent, 在RegisterListener()階段會自動發布早期事件.

什么是早期的事件監聽器呢? 早對應的就是晚了. 早期指的是多早呢?

早期事件指的是事件監聽器還沒有注冊到事件多播器的時候.

早期定義的事件不需要手動的publishEvent, 在RegisterListener()階段會自動發布早期事件.

在這里就定義了一個集合, 這個集合就是后面事件監聽器集合. 在這里只是進行的初始化

 

5. 初始化保存早期事件的集合

this.earlyApplicationEvents = new LinkedHashSet<>();

在第一步: 對事件的操作就是初始化. 一共初始化了兩個集合, 一個是早期事件監聽器集合, 一個是早期的事件集合

 

2.2 初始化bean工廠 

 我們現在經常使用的beanFactory有兩種,一種是xml方式的, 另一種是注解方式的. 其實使用注解的更多一些. xml和注解方式的bean工廠在初始化的時候也是有區別的. 

 從上圖可以看出, 獲取兩種方式的bean工廠的區別

1. AbstractRefreshableApplicationContext: 基於xml配置文件的方式
2. GenericApplicationContext: 基於注解的方式.
基於注解實現的里面代碼很簡單, 只是刷新的beanFactory. 沒有耦合加載beanDefinition的流程. 基於xml實現的代碼, 里面耦合了加載beanDefinition

先來看看基於注解方式的, 基於注解方式只是指定了bean工廠的序列化ID

@Override
    protected final void     refreshBeanFactory() throws IllegalStateException {
        if (!this.refreshed.compareAndSet(false, true)) {
            throw new IllegalStateException(
                    "GenericApplicationContext does not support multiple refresh attempts: 
                just call 'refresh' once
"); } // 指定bean工廠的序列化ID this.beanFactory.setSerializationId(getId()); }

再來看看基於xml方式的, 基於xml方式的 除了指定了bean工廠的序列化id, 還耦合加載了beanDefinition

@Override
    protected final void refreshBeanFactory() throws BeansException {
        // 判斷bean工廠是否初始化過, 如果已經初始化過那么銷毀並關閉
        if (hasBeanFactory()) {
            destroyBeans(); closeBeanFactory();
        }
        try {
            // 重新創建一個bean工廠
            DefaultListableBeanFactory beanFactory = createBeanFactory(); // 設置序列化id
            beanFactory.setSerializationId(getId());
            // 設置個性化屬性
            customizeBeanFactory(beanFactory);
            // 加載BeanDefinition loadBeanDefinitions(beanFactory); this.beanFactory = beanFactory;
        }
        catch (IOException ex) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + 
              getDisplayName(), ex); } }

 看上面的步驟. 

1. 先看看是否已經有過工廠了, 如果已經有了,那么銷毀,關閉

2. 重新創建了一個空的新的工廠

3. 設置新工廠的序列化id

4. 設置個性化屬性bean

5. 加載bean定義. 我們看到, 使用xml方式會加載bean定義

6. 返回bean工廠對象

這一步: 主要是初始化了bean工廠

 

2.3 對bean工廠進行填充屬性prepareBeanFactory(beanFactory);

 這一步是和監聽器有關系的. 我們先來看看源碼

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        // Tell the internal bean factory to use the context's class loader etc.
        // 設置bean工廠的類加載器為當前的application應用的加載器
        beanFactory.setBeanClassLoader(getClassLoader());
        // 為bean工廠設置標准的SPEL表達式解析器對象(StandardBeanExpressionResolver)
        beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
        // 為bean工廠設置一個PropertiesEditor屬性資源編輯器(用於后面給bean對象賦值)
        beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

        // Configure the bean factory with context callbacks.
        /**
         * 注冊一個完整的ApplicationContextAwareProcessor后置處理器, 用來處理ApplicationContextAware
         * ApplicationContextAwareProcessor是一個bean的后置處理器. 怎么使用呢?
         *
         * 在bean初始化完成以后, 會調用一堆的bean后置處理器.
         * 在初始化的地方,其實只調用了三個bean后置處理器. 那么其他的后置處理器是什么時候調用的呢?
         * 就是在這里, 這里注冊了 ApplicationContextAwareProcessor.
         * 在ApplicationContextAwareProcessor#invokeAwareInterfaces方法里調用了其他的aware
         * 那么invokeAwareInterfaces方法是在哪里調用呢?
         * 是在ApplicationContextAwareProcessor#postProcessBeforeInitialization調用的
         * postProcessBeforeInitialization是在bean初始化之前會調用的后置處理器
         *
         * 然后在通過addBeanPostProcessor()方法, 將bean的后置處理器添加到beanPostProcessors集合中
         */ beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); /**
         * 忽略部分接口的函數方法, 在populateBean(創建bean的第二步:屬性賦值)時
         * 因為下面接口都有set***方法, 這些方法不特殊處理將會自動注入到容器中.
         *
         * 忽略了這么多的Aware, 這是怎么回事呢? 因為Aware里面的方法都是以set開頭的. 當在創建bean, 設置屬性的時候,
         * 會給帶有set+屬性名的方法賦值. 而Aware的這些方法要忽略掉, 為什么忽略掉呢?
         *
         * 比如:EnvironmentAware 里面設置了一些環境變量, 這些環境變量是不需要進行屬性裝配的, 所以要把他們排除掉
         */
        beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
        beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
        beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
        beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

        // BeanFactory interface not registered as resolvable type in a plain factory.
        // MessageSource registered (and found for autowiring) as a bean.
        /**
         * 將beanFactory類型的實例注冊解析
         *
         * 當注冊了依賴解析以后, 例如當注冊了對BeanFactory.class的解析依賴后,
         * 當bean屬性注入的時候, 一旦檢測到屬性為beanFactory類型. 便會將BeanFactory的實例注冊解析
         * 為什么呢?
         * 比如:
         * @Autowired
         * ApplicationContext applicationContext 為什么能夠自動裝配, 通過@Autowired引入呢? 就是在這里裝配的.
         * 這個也是在注入屬性popularBean的時候體現的
         *
         */
        beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
        beanFactory.registerResolvableDependency(ResourceLoader.class, this);
        beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
        beanFactory.registerResolvableDependency(ApplicationContext.class, this);

        // Register early post-processor for detecting inner beans as ApplicationListeners.
        // 注冊事件監聽器探測器后置處理器接口, ApplicationListenerDetector 解析接口方式的監聽器 beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this)); // Detect a LoadTimeWeaver and prepare for weaving, if found.
        if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
            beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
            // Set a temporary ClassLoader for type matching.
            beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
        }

        // Register default environment beans.
        if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
            beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
        }
        if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
            beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
        }
        if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
            beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
        }
    }

1. 設置bean工廠的類加載器為: 當前的application應用的加載器

2. 為bean工廠設置標准的SPEL表達式解析器對象, 這個解析器對象是誰呢? 就是StandardBeanExpressionResolver

3. 為bean工廠設置一個PropertiesEditor屬性資源編輯器, 用於后面給bean對象賦值

4. 給bean工廠注冊了一個ApplicationContextAwareProcessor后置處理器. 這里說說這個后置處理器類. 這個類有什么作用呢?

在bean初始化完成以后, 會調用一堆的bean后置處理器

在doCreateBean()中找到第三步: 初始化bean

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
        if (System.getSecurityManager() != null) {
            AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                // 在初始化完成以后, 調用aware
                invokeAwareMethods(beanName, bean);
                return null;
            }, getAccessControlContext());
        }
        else {
            // 在初始化的時候, 會調用很多的aware.  invokeAwareMethods(beanName, bean);
        }

        Object wrappedBean = bean;
        if (mbd == null || !mbd.isSynthetic()) {
            // 在初始化之前調用bean的后置處理器
            wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
        }

        try {
            // 調用初始化方法
            invokeInitMethods(beanName, wrappedBean, mbd);
        }
        catch (Throwable ex) {
            throw new BeanCreationException(
                    (mbd != null ? mbd.getResourceDescription() : null),
                    beanName, "Invocation of init method failed", ex);
        }
        if (mbd == null || !mbd.isSynthetic()) {
            // 再初始化之后調用bean的后置處理器
            wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }

        return wrappedBean;
    }

我們看到, 在初始化bean的時候, 調了很多Aware, invokeAwareMethods(beanName, bean);

/**
     * 這里主要有三類aware
     * @param beanName
     * @param bean
     */
    private void invokeAwareMethods(final String beanName, final Object bean) {
        /**
         * 在這里調用的aware只有三類, 我們去BeanFactory中看, 他有一大堆的aware要調用,
         * 那么其他的aware是在哪里調用的呢?
         */
        if (bean instanceof Aware) {
            // 實現了BeanNameAware的bean
            if (bean instanceof BeanNameAware) {
                ((BeanNameAware) bean).setBeanName(beanName);
            }
            // 實現了BeanClassLoaderAware接口
            if (bean instanceof BeanClassLoaderAware) {
                ClassLoader bcl = getBeanClassLoader();
                if (bcl != null) {
                    ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
                }
            }
            // 實現了BeanFactoryAware
            if (bean instanceof BeanFactoryAware) {
                ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
            }
        }
    }

如上代碼, 我們看到, 其實知道用了3中類型的Aware. 分別是BeanNameAware, BeanClassLoaderAware 和 BeanFactoryAware.

那么其他的Aware呢? 我們看beanFactory接口的注釋可以看到, 會調用很多Aware

 

在初始化的地方,其實只調用了三個bean后置處理器. 那么其他的后置處理器是什么時候調用的呢?

就是在這里, 這里注冊了 ApplicationContextAwareProcessor.

在ApplicationContextAwareProcessor#invokeAwareInterfaces方法里調用了其他的aware

/**
     * 判斷bean是否實現了各種Aware
     * @param bean
     */
    private void invokeAwareInterfaces(Object bean) {
        if (bean instanceof EnvironmentAware) {
            ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
        }
        if (bean instanceof EmbeddedValueResolverAware) {
            ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
        }
        if (bean instanceof ResourceLoaderAware) {
            ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
        }
        if (bean instanceof ApplicationEventPublisherAware) {
            ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
        }
        if (bean instanceof MessageSourceAware) {
            ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
        }
        if (bean instanceof ApplicationContextAware) {
            ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
        }
    }

 而這個方法, 什么時候執行呢? 在初始化之前調用Bean的后置處理器執行的ApplicationContextAwareProcessor#postProcessBeforeInitialization

@Override
    @Nullable
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
                bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
                bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)){
            return bean;
        }

        AccessControlContext acc = null;

        if (System.getSecurityManager() != null) {
            acc = this.applicationContext.getBeanFactory().getAccessControlContext();
        }

        if (acc != null) {
            AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                invokeAwareInterfaces(bean); return null;
            }, acc);
        }
        else {
            invokeAwareInterfaces(bean);
        }

        return bean;
    }

 然后在通過addBeanPostProcessor()方法, 將bean的后置處理器添加到beanPostProcessors集合中.

5. 忽略部分接口的函數方法. 這些接口主要是Aware.  

beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class); beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class); beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class); beanFactory.ignoreDependencyInterface(MessageSourceAware.class); beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

 忽略了這么多的Aware, 這是怎么回事呢?為什么忽略掉呢? 因為Aware里面的方法都是以set開頭的. 當在創建bean, 設置屬性的時候,

會給帶有set+屬性名的方法賦值.在populateBean(創建bean的第二步:屬性賦值)時 因為下面接口都有set***方法, 這些方法不特殊處理將會自動注入到容器中.

比如:EnvironmentAware 里面設置了一些環境變量, 這些環境變量是不需要進行屬性裝配的, 所以要把他們排除掉

6. 將beanFactory類型的實例注冊解析

beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this); beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this); beanFactory.registerResolvableDependency(ApplicationContext.class, this);
當注冊了依賴解析以后, 例如當注冊了對BeanFactory.class的解析依賴后,
當bean屬性注入的時候, 一旦檢測到屬性為beanFactory類型. 便會將BeanFactory的實例注冊解析
為什么呢?
比如:
@Autowired
ApplicationContext applicationContext; .
為什么能夠自動裝配, 通過@Autowired引入呢? 就是在這里裝配的
這個也是在注入屬性popularBean的時候體現的

7. 注冊了一個解析接口方式的監聽器的 BeanPostProcessor. 

beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

我們來看看ApplicationListenerDetector 類, 其下的 postProcessAfterInitialization方法, 是在createBean的第三步初始化之后執行的bean的后置處理器.

 @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        if (bean instanceof ApplicationListener) { // potentially not detected as a listener by getBeanNamesForType retrieval
            Boolean flag = this.singletonNames.get(beanName);
            if (Boolean.TRUE.equals(flag)) {
                // singleton bean (top-level or inner): register on the fly
                /* * 注冊接口類型的監聽器. 將其添加到applicationContext中 * 之所以要在這里在加一次, 是為了處理懶加載情況 */
                this.applicationContext.addApplicationListener((ApplicationListener<?>) bean);
            }
            else if (Boolean.FALSE.equals(flag)) {
                // 這里是處理早期事件.
                if (logger.isWarnEnabled() && !this.applicationContext.containsBean(beanName)) {
                    // inner bean with other scope - can't reliably process events
                    logger.warn("Inner bean '" + beanName + "' implements ApplicationListener interface " +
                            "but is not reachable for event multicasting by its containing ApplicationContext " +
                            "because it does not have singleton scope. Only top-level listener beans are allowed " +
                            "to be of non-singleton scope.");
                }
                this.singletonNames.remove(beanName);
            }
        }
        return bean;
    }

我們看這個方法, 方法一進來就判斷,是否是實現了ApplicationListener接口. 也就是說, 上面我們輸了注冊監聽器有兩種方式, 一種是接口方式, 另一種是注解方式. 這里解析的是實現接口的方式.

在這里,我們要先建立一個印象, 因為后面還會說到他. 為什么呢? 因為接口方式的監聽器在兩個地方被調用, 一個是這里, 另一個是在refresh()后面的流程registerListener()的時候. 那么, 為什么要有兩次調用監聽器呢? 我們后面再說

2.4 postProcessBeanFactory(beanFactory); 這是一個擴展方法, 可以初始化剩余的Aware. 

我們是AbstractApplicationContext沒有實現, 但AbstractRefreshableWebApplicationContext類. 里面就定義了postProcessBeanFactory(beanFactory)

在里面注冊了ServletContextAwareProcessor

beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig));

beanFactory.ignoreDependencyInterface(ServletContextAware.class);

beanFactory.ignoreDependencyInterface(ServletConfigAware.class);

上面我們知道在 BeanFactory 里定義了需要調用的很多Aware. 但是有幾個Aware還沒有說到.

比如: ServletContextAware's {@code setServletContext} : ServletContextAware, 可以獲得當前的ServletContextAware

添加了這個Aware以后, 我們就可以實現一個ServletContextAware的接口.

到這里, 我們就知道所有的aware都在哪里被調用了.

2.5 調用bean工廠的后置處理器, 解析配置類

 這一步就略過了,之前重點說過這一步

2.6 registerBeanPostProcessors(beanFactory); 注冊bean后置處理器, 這里主要是和AOP有關系

這里和監聽器關系不太大, 也暫時略過

2.7  initMessageSource(); 初始化國際化資源處理器

2.8 initApplicationEventMulticaster();創建事件多播器

 事件多播器管理所有的事件監聽器. 並廣播事件給對應的監聽器

當我們調用ctx.publishEvent(new OrderEvent(order, "減庫存"))的時候. 就會去通知所有監聽了OrderEvent事件的事件監聽器,
那么, 是由誰去負責通知呢? 

就是由EventMulticaster(事件多播器)將事件播報出去的.

 首先, 判斷有沒有最定義的事件多播器. 如果有, 那么直接將其添加到容器中. 如果沒有, 就新建一個SimpleApplicationEventMulticaster類型的事件多播器, 然后將其添加到beanFactory中.

那么, 事件多播器都做了什么事情呢? 具體來看一看SimpleApplicationEventMulticaster類. 

 這是SimpleApplicationEventMulticaster的繼承結構. 繼承了AbstractApplicationEventMulticaster, 而AbstractApplicationEventMulticaster又實現了ApplicationEventMulticaster. 我們看看在ApplicationEventMulticaster中都對應了哪些接口

public interface ApplicationEventMulticaster {
    void addApplicationListener(ApplicationListener<?> listener);
    void addApplicationListenerBean(String listenerBeanName);
    void removeApplicationListener(ApplicationListener<?> listener);
    void removeApplicationListenerBean(String listenerBeanName);
    void removeAllListeners();  
    void multicastEvent(ApplicationEvent event);
    void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType);
}

 看名字就知道了, 做了兩件事, 一個是管理事件監聽器, 另一個是廣播事件. 

我們看AbstractApplicationEventMulticaster如何實現這幾個接口的

/**
     * AbstractApplicationEventMulticaster管理了所有的監聽器.
     * 當我們注冊一個監聽器以后, 就會通過addApplicationListener方法添加到事件多播器中.
     * @param listener the listener to add
     */
    @Override
    public void addApplicationListener(ApplicationListener<?> listener) {
        synchronized (this.retrievalMutex) {
            // Explicitly remove target for a proxy, if registered already,
            // in order to avoid double invocations of the same listener.
            Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
            if (singletonTarget instanceof ApplicationListener) {
                this.defaultRetriever.applicationListeners.remove(singletonTarget);
            }
            this.defaultRetriever.applicationListeners.add(listener);
            this.retrieverCache.clear();
        }
    }

 這是添加事件監聽器.

在SimpleApplicationEventMulticaster里面, 定義了廣播事件監聽器

@Override
    public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
        ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
        //獲取線程池
        Executor executor = getTaskExecutor();
        // 從多播器中獲取所有的監聽器
        for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
            // 拿到了監聽器
            if (executor != null) {
                // 異步調用廣播事件
                executor.execute(() -> invokeListener(listener, event));
            }
            else {
                // 同步調用廣播事件 invokeListener(listener, event);
            }
        }
    }

 這里有兩種方式, 一種是同步的方式, 另一種是異步的方式. 根據設置的eventType來決定的. 其實異步的方式就是建立了一個新的線程

我么你來看一下調用事件監聽器廣播事件

invokeListener#doInvokeListener

private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
        try {
            // 最終調用的是監聽器的onApplicationEvent方法. 這個方法就是每一個監聽器都會自定義的方法. listener.onApplicationEvent(event);
        }
        catch (ClassCastException ex) {
            String msg = ex.getMessage();
            if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
                // Possibly a lambda-defined listener which we could not resolve the generic event type for
                // -> let's suppress the exception and just log a debug message.
                Log logger = LogFactory.getLog(getClass());
                if (logger.isTraceEnabled()) {
                    logger.trace("Non-matching event type for listener: " + listener, ex);
                }
            }
            else {
                throw ex;
            }
        }
    }

 最終調用的是監聽器的onApplicationEvent方法. 這個方法就是每一個監聽器都會自定義的方法.

listener.onApplicationEvent(event);

 2.9 onRefresh();這是一個擴展方法. 這里沒有具體實現.spring boot也是從這個方法進行啟動

2.10 注冊監聽器registerListeners();

 注冊監聽器這里一共做了三件事:

1. 將事件監聽器注冊到多播器上

2. 廣播早期的事件

3. 清空早期事件.

到此步驟之前, 上面都是有早期事件的, 后面就沒有早期事件了,因為這一步就都清空了. 后面也不會在進行自動廣播了, 自動廣播的就是早期事件.

protected void registerListeners() {
        // Register statically specified listeners first.
        /** * 第一步, 獲取所有的事件監聽器集合. * 通常, 這個時候, 事件監聽器集合是空的, 除非手動調用allApplicationListeners()注冊事件監聽器 */
        for (ApplicationListener<?> listener : getApplicationListeners()) {
            // 將監聽器注冊到多播器上
            getApplicationEventMulticaster().addApplicationListener(listener);
        }

        
        /** * 第二步: 注冊接口方式的監聽器 * 獲取beanDefinition中 ApplicationListener 類型的監聽器. 也就是說, 使用接口方式定義的監聽器
      * 就可以在這里被注冊到多播器的 * 這里是從BeanDefinition中拿的, 我們自定義了 OrderEventListenter 監聽器, 那么會不會拿到呢? * 我們知道監聽器的實現有兩種方式, 一種是接口方式, 一種是注解方式. * 如果OrderEventListenter采用的是接口方式, 那么就可以拿到. 因為它實現了ApplicationListener.拿到了,
     * 就把監聽器注冊到多播器上. * 如果是注解方式, 那就拿不到了 * */
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) { // 把監聽器注冊到多播器上 getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName); } /** * 第三步: 獲取早期的事件, 然后廣播早期事件. * 這些早期事件是在第一步 prepareRefresh 注冊的. * */ Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents; // 在這里將早期事件清空, 清空完以后, 就沒有早期事件了. this.earlyApplicationEvents = null; if (!CollectionUtils.isEmpty(earlyEventsToProcess)) { for (ApplicationEvent earlyEvent : earlyEventsToProcess) { getApplicationEventMulticaster().multicastEvent(earlyEvent); } } }

如上源碼所示: 

第一步. 獲取所有的事件監聽器集合, 通常這個時候, 事件監聽器的集合都是空的, 除非我們手動調用allApplicationListeners()注冊事件監聽器

第二步: 注冊接口方式的監聽器. 注意,是接口方式的. 通常我們自定義的監聽器.  有兩種類型, 接口方式和注解方式. 如果使用的是接口方式. 那么就是在這里被注冊的.如果是注解方式.不在這里注冊.

getBeanNamesForType(ApplicationListener.class, true, false);
掃描獲取ApplicationListener類型的監聽器.

然后將其注冊到多播器上. 我們知道多播器的兩個主要功能, 管理監聽器和廣播事件.

getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);

第三步: 獲取早期事件, 然后廣播早期事件. 早期事件我們之前已經說過了, 是在第一步prepareRefresh()方法里注冊的.

隨后, 立即清空早期事件集合. 然后廣播事件. 這樣早期定義好的事件就都被廣播出去了, 並且只能執行一次, 不會被再次執行.

/**
 * 第三步: 獲取早期的事件, 然后廣播早期事件. 
 * 這些早期事件是在第一步 prepareRefresh 注冊的.
 * 
 */
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents; // 在這里將早期事件清空, 清空完以后, 就沒有早期事件了.
this.earlyApplicationEvents = null; if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
    for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
        getApplicationEventMulticaster().multicastEvent(earlyEvent);
    }
}

2.11 實例化剩余的單實例bean

 這個方法就是循環遍歷BeanDefinitionMap, 調用getBean, 去生產剩余的bean, 之前詳細研究過這個步驟, 這里就不說了

2.12 完成refresh()操作, 發布刷新事件 

protected void finishRefresh() {
    // Clear context-level resource caches (such as ASM metadata from scanning).
    // 清除上下文緩存
    clearResourceCaches();

    // Initialize lifecycle processor for this context.
    // 注冊lifecycleProcessor聲明周期處理器
    // 作用: 當ApplicationContext啟動或停止時, 他會通過LifecycleProcessor來與所有聲明的bean進行交互
    initLifecycleProcessor();

    // Propagate refresh to lifecycle processor first.
    // 為實現了SmartLifeCycle並且isAutoStartup, 自動啟動的Lifecycle調用start()方法
    getLifecycleProcessor().onRefresh();

    // Publish the final event. // 發布容器refresh完畢的事件. // 發布的是什么事件呢? 是ContextRefreshedEvent事件. publishEvent(new ContextRefreshedEvent(this)); // Participate in LiveBeansView MBean, if active.
    LiveBeansView.registerApplicationContext(this);
}

在這一步: 發布了容器Refreshed事件. 也就是容器啟動完成的事件. 

到這里, 我們來看看publicshEvent的具體實現

/**
     * 發布事件給所有的監聽器
     * Publish the given event to all listeners.
     * @param event the event to publish (may be an {@link ApplicationEvent}
     * or a payload object to be turned into a {@link PayloadApplicationEvent})
     * @param eventType the resolved event type, if known
     * @since 4.2
     */
    protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
        Assert.notNull(event, "Event must not be null");

        // Decorate event as an ApplicationEvent if necessary
        ApplicationEvent applicationEvent;

        /** * 第一步: 獲取事件 */
        if (event instanceof ApplicationEvent) {
            // 處理接口類型的事件
            applicationEvent = (ApplicationEvent) event;
        }
        else {
            applicationEvent = new PayloadApplicationEvent<>(this, event);
            if (eventType == null) {
                eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
            }
        }

        /** * 第二步: 發布事件 */
        // Multicast right now if possible - or lazily once the multicaster is initialized
        if (this.earlyApplicationEvents != null) {
            this.earlyApplicationEvents.add(applicationEvent);
        }
        else {
            /*
             * 調用事件多播器, 將這個事件發布出去
             * 事件多播器是什么時候注冊的呢? 
        * 就是在refresh()初始化的時候, 調用initApplicationEventMulticaster(); 初始化的事件多播器
*/ 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); } } }

這里做了如下幾件事

1. 獲取事件

2. 廣播事件

3. 廣播事件給父類監聽器.

詳細代碼可以看注釋

接下來看一下,具體的multicastEvent(...)

@Override
    public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
        ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
        //獲取線程池
        Executor executor = getTaskExecutor(); // 從多播器中獲取所有的監聽器
        for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
            // 拿到了監聽器
            if (executor != null) {
                // 異步調用廣播事件 executor.execute(() -> invokeListener(listener, event));
            }
            else {
                // 同步調用廣播事件
                invokeListener(listener, event);
            }
        }
    }

這里首先會去獲取線程池. 看看有沒有重新定義線程池, 如果有這里executor就不是空的.

廣播事件有兩種形式, 一種是同步, 一種是異步. 如果executor線程池不空, 就以異步的形式廣播, 否則就以同步的形式廣播. 

那么,我們如何自定義同步或者異步呢? 也是有兩種方式

第一種方式: 自定義事件多波器, 並指定taskExcutor

  @Bean(name = "applicationEventMulticaster")
    public ApplicationEventMulticaster simpleApplicationEventMulticaster() {
        SimpleApplicationEventMulticaster eventMulticaster
                = new SimpleApplicationEventMulticaster();

        //ThreadPoolTaskExecutor
      // 這里指定了 taskExecutor, 就會使用異步的方式去執行
        eventMulticaster.setTaskExecutor(new SimpleAsyncTaskExecutor());
        return eventMulticaster;
    }

第二種方式, 在事件監聽器上使用注解@Async

@Component
@Async public class OrderEventListenter implements ApplicationListener<OrderEvent> {
    /**
     * 當某一個事件發布的時候, 就會觸發事件監聽器
     * @param event the event to respond to
     */
    @Override
    public void onApplicationEvent(OrderEvent event) {
        if (event.getName().equals("減庫存")) {
            System.out.println("事件監聽器  監聽到  減庫存");
        }
    }
}

接下來看看如何廣播事件的. 

/**
     * Invoke the given listener with the given event.
     * @param listener the ApplicationListener to invoke
     * @param event the current event to propagate
     * @since 4.1
     */
    protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
        ErrorHandler errorHandler = getErrorHandler();
        if (errorHandler != null) {
            try {
                doInvokeListener(listener, event);
            }
            catch (Throwable err) {
                errorHandler.handleError(err);
            }
        }
        else {
            doInvokeListener(listener, event);
        }
    }

 

private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
        try {
            // 最終調用的是監聽器的onApplicationEvent方法. 這個方法就是每一個監聽器都會自定義的方法. listener.onApplicationEvent(event);
        }
        catch (ClassCastException ex) {
            String msg = ex.getMessage();
            if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
                // Possibly a lambda-defined listener which we could not resolve the generic event type for
                // -> let's suppress the exception and just log a debug message.
                Log logger = LogFactory.getLog(getClass());
                if (logger.isTraceEnabled()) {
                    logger.trace("Non-matching event type for listener: " + listener, ex);
                }
            }
            else {
                throw ex;
            }
        }
    }

其實,具體執行的邏輯, 就是我們在監聽器中定義的onApplicationEvent(event)方法中的邏輯實現.

 

三. 注冊接口方式的監聽器

在上面的源碼分析中, 注冊接口方式的監聽器, 其實是由兩個地方. 

第一個: 在第十步registerListener()

protected void registerListeners() {
        .....
        /** * 第二步: 注冊接口方式的監聽器 * 獲取beanDefinition中 ApplicationListener 類型的監聽器. 
      * 也就是說, 使用接口方式定義的監聽器就可以在這里被注冊到多播器的 * 這里是從BeanDefinition中拿的, 我們自定義了 OrderEventListenter 監聽器, 那么會不會拿到呢? * 我們知道監聽器的實現有兩種方式, 一種是接口方式, 一種是注解方式. * 如果OrderEventListenter采用的是接口方式, 那么就可以拿到. 因為它實現了ApplicationListener.
      * 拿到了, 就把監聽器注冊到多播器上. * 如果是注解方式, 那就拿不到了 *
*/ String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false); for (String listenerBeanName : listenerBeanNames) { // 把監聽器注冊到多播器上
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName); } ..... }

 另一個: 是在第三步進行屬性填充的時候注冊的

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        ......
        /**
         * 注冊事件監聽器探測器后置處理器接口, ApplicationListenerDetector 解析接口方式的監聽器
         */ beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

        ......
    }

在准備屬性的方法里, 有一個注冊時間監聽器探測器后置處理. 在這個監聽器的探測器里面, 進行了注冊.

來看看ApplicationListenerDetector

class ApplicationListenerDetector implements DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor {

    ....../**
     * 初始化后的bean后置處理器
     *
     * 這個方法是在 registerListener 之后執行的, 在registerListener()方法里注冊過一次接口方式的監聽器.
     * 在這里還會在注冊一次.
     *
     * 問題: 為什么同一個監聽器, 要在兩個地方注冊呢?
     * 第一次添加的是監聽器的名字, 第二次添加的是bean實體. 那為什么要添加兩次呢?
     * 這是為了處理帶有@Lazy懶加載方式的bean. 懶加載的bean是不會在初始化容器的時候創建bean的.
     *
     * 比如, 我給監聽器類加上一個@Lazy, 那么他就不會走bean的后置處理器, 因為bean的后置處理器, 是在bean創建過程中調用的.
     * 那什么時候會被調用呢? 在真正使用的時候. 比如調用 ctx.publishEvent(new OrderEvent(order, "減庫存"));
     * 馬上就要用到了, 所以, 這時候回去調bean的后置處理器. 執行代碼看一下效果
     *
     *
     * @param bean the new bean instance
     * @param beanName the name of the bean
     * @return
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        if (bean instanceof ApplicationListener) {
            // potentially not detected as a listener by getBeanNamesForType retrieval
            Boolean flag = this.singletonNames.get(beanName);
            if (Boolean.TRUE.equals(flag)) {
                // singleton bean (top-level or inner): register on the fly
                /* * 注冊接口類型的監聽器. 將其添加到applicationContext中 * 之所以要在這里在加一次, 是為了處理懶加載情況 */
                this.applicationContext.addApplicationListener((ApplicationListener<?>) bean);
            }
            else if (Boolean.FALSE.equals(flag)) {
                // 這里是處理早期事件.
                if (logger.isWarnEnabled() && !this.applicationContext.containsBean(beanName)) {
                    // inner bean with other scope - can't reliably process events
                    logger.warn("Inner bean '" + beanName + "'implements ApplicationListener interface" +
                            "but is not reachable for event multicasting by its containing ApplicationContext" +
                            "because it does not have singleton scope.Only top-level listener beans are allowed" +
                            "to be of non-singleton scope.");
                }
                this.singletonNames.remove(beanName);
            }
        }
        return bean;
    }
.......
}

我們看到在ApplicationListenerDetector中定義了方法postProcessAfterInitialization. 這個方法會在創建屬性的第三步執行完以后調用. 第三步是初始化. 看名字也知道是初始化之后調用的后置處理器. 在這里, 注冊了接口類型的監聽器

this.applicationContext.addApplicationListener((ApplicationListener<?>) bean);

那么, 為什么要有兩次注冊呢?

其實這里是為了解決懶加載的問題. 因為,如果一個類是懶加載的類, 那么他只有真正被調用的時候才回去加載. 所以, 也就是在類進行初始化以后才會被調用. 因此在初始化之后再次加載了接口類型的監聽器. 

四. 解析注解方式的監聽器

整個流程走完, 我們都只看到接口方式的監聽器注冊的地方. 那么注解類型的監聽器是什么時候被創建的呢?

首先, 注解是何時被解析的? 我們知道BeanDefinitionReader在解析創世紀的類的時候, 注冊了很多創世紀的類.其中就有兩個是用於負責處理@EventListener注解的

再來回顧一下這段代碼

public static Set<BeanDefinitionHolder>  registerAnnotationConfigProcessors(
            BeanDefinitionRegistry registry, @Nullable Object source) {

        // 獲取到beanFactory
        DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
        /**
         * 判斷beanFactory中是否有AnnotationAwareOrderComparator和ContextAnnotationAutowireCandidateResolver
         * 沒有則添加
         */
        if (beanFactory != null) {
            if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
                beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
            }
            if (!(beanFactory.getAutowireCandidateResolver() instanceof 
                  ContextAnnotationAutowireCandidateResolver)) { beanFactory.setAutowireCandidateResolver(
new ContextAnnotationAutowireCandidateResolver()); } } // BeanDefinitionHolder: 為BeanDefinition設置名字和別名 Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8); // 如果registry中沒有ConfigurationClassPostProcessor配置類后置處理器, 就添加一個 if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class); def.setSource(source); // 構建BeanDefinitionHolder, 並添加到beanDefs beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)); } // 如果rigistry中, 沒有AutowiredAnnotationBeanPostProcessor Autowired注解bean的后置處理器, 則添加一個 if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class); def.setSource(source); // 構建BeanDefinitionHolder, 並添加到beanDefs beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)); } // Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor. // 檢查對JSR-250的支持, 如果rigistry中沒有 CommonAnnotationBeanPostProcessor 通用注解后置處理器, 則添加一個 if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class); def.setSource(source); // 構建BeanDefinitionHolder, 並添加到beanDefs beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)); } // Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor. // 檢查對jpa的支持, 如果不包含 internalPersistenceAnnotationProcessor, 持久化注解處理器, 就添加一個 if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(); try { def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, AnnotationConfigUtils.class.getClassLoader())); } catch (ClassNotFoundException ex) { throw new IllegalStateException( "Cannot load optional framework class: " +
                    PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex); } def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)); }
/** * 下面這兩個注解是用來解析@EventListener的 */ // 檢查對事件監聽的支持, 如果不包含事件監聽處理器 internalEventListenerProcessor, 就添加一個 /* * EventListenerMethodProcessor : 既不是bean的后置處理器, 也不是bean工廠的后置處理器 * 那么EventListenerMethodProcessor是在哪里被調用,並且解析注解方式的監聽器呢? * * 下面看一下EventListenerMethodProcessor的繼承結構圖. * 1. 實現了SmartInitializingSingleton接口 : * 2. 實現了ApplicationContextAware接口 : 因為要往容器中注入bean, 所以,里面要使用容器的上下文,
      * 將容器以Aware的方式set進來 * 3. 實現了BeanFactoryPostProcessor接口 : * *
*/ if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME)); } // 如果不包含事件監聽工廠處理器 internalEventListenerFactory , 就添加一個 if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME)); } return beanDefs; }

 如上圖就是注冊的創世紀的處理器. 最后兩個就是用來處理@EventListener注解的.

下面來看看EventListenerMethodProcessor事件監聽器處理器,

首先, 看一下EventListenerMethodProcessor的繼承結構圖.

 

 EventListenerMethodProcessor實現了三個接口. 

1.實現了SmartInitializingSingleton接口

2. 實現了ApplicationContextAware接口 : 因為要往容器中注入bean, 所以,里面要使用容器的上下文, 將容器以Aware的方式set進來 

3. 實現了BeanFactoryPostProcessor接口

SmartInitializingSingleton接口在哪里被用到了呢? 

在refresh()#finishBeanFactoryInitialization(beanFactory); 實例化剩余的單例bean的過程中

在DefaultListableBeanFactory#preInstantiateSingletons()方法. 有兩次循環遍歷beanNames

@Override
    public void preInstantiateSingletons() throws BeansException {
        if (logger.isTraceEnabled()) {
            logger.trace("Pre-instantiating singletons in " + this);
        }

        // Iterate over a copy to allow for init methods which in turn register new bean definitions.
        // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
        // 獲取容器中所有bean定義的名字
        List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

        // Trigger initialization of all non-lazy singleton beans...
        /** * 第一步: 循環bean定義的name, 創建bean */
        for (String beanName : beanNames) {
            // 獲取bean定義
            RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
            // 生產bean定義的條件: 不是抽象的, 是單例的, 不是懶加載的. 符合這個標准的, 最后才會調用getBean()生產bean
            if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
                // 這里判斷是不是工廠bean, 這里和BeanFactory不是一個意思, 判斷當前這個bean是否實現了beanFactory的接口
                if (isFactoryBean(beanName)) {
                    Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
                    if (bean instanceof FactoryBean) {
                        // 將bean轉換為FactoryBean 工廠bean
                        final FactoryBean<?> factory = (FactoryBean<?>) bean;
                        boolean isEagerInit;
                        if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                            isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
                                            ((SmartFactoryBean<?>) factory)::isEagerInit,
                                    getAccessControlContext());
                        }
                        else {
                            isEagerInit = (factory instanceof SmartFactoryBean &&
                                    ((SmartFactoryBean<?>) factory).isEagerInit());
                        }

                        if (isEagerInit) {
                            // 獲取bean
                            getBean(beanName);
                        }
                    }
                }
                else {
                    // 第二步: 調用getBean
                    getBean(beanName);
                }
            }
        }

        // Trigger post-initialization callback for all applicable beans...
        /** * 第二步: 循環bean定義的name, 解析是否有實現了SmartInitializingSingleton接口的類 * 到這里, bean都已經被創建完了 */
        for (String beanName : beanNames) {
            // 從緩存中得到實例instance
            Object singletonInstance = getSingleton(beanName);
            if (singletonInstance instanceof SmartInitializingSingleton) {
                final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
                if (System.getSecurityManager() != null) {
                    AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                        smartSingleton.afterSingletonsInstantiated();
                        return null;
                    }, getAccessControlContext());
                }
                else {
                    smartSingleton.afterSingletonsInstantiated();
                }
            }
        }
    }

第一次循環, 是創建bean, 並獲取bean

第二次循環, 是在所有的bean都已經創建完以后, 如果singletonInstance是SmartInitializingSingleton的實例, 則調用afterSingletonsInstantiated()方法. 

以下是EventListenerMethodProcessor#afterSingletonsInstantiated()方法實現 

@Override
    public void afterSingletonsInstantiated() {
        // 從spring容器中獲取EventListenerFactoryBean
        ConfigurableListableBeanFactory beanFactory = this.beanFactory;
        Assert.state(this.beanFactory != null, "No ConfigurableListableBeanFactory set");
        // 獲取所有類型的bean
        String[] beanNames = beanFactory.getBeanNamesForType(Object.class);
        for (String beanName : beanNames) {
            if (!ScopedProxyUtils.isScopedTarget(beanName)) {
                Class<?> type = null;
                try {
                    type = AutoProxyUtils.determineTargetClass(beanFactory, beanName);
                }
                catch (Throwable ex) {
                    // An unresolvable bean type, probably from a lazy bean - let's ignore it.
                    if (logger.isDebugEnabled()) {
                        logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
                    }
                }
                if (type != null) {
                    if (ScopedObject.class.isAssignableFrom(type)) {
                        try {
                            Class<?> targetClass = AutoProxyUtils.determineTargetClass(
                                    beanFactory, ScopedProxyUtils.getTargetBeanName(beanName));
                            if (targetClass != null) {
                                type = targetClass;
                            }
                        }
                        catch (Throwable ex) {
                            // An invalid scoped proxy arrangement - let's ignore it.
                            if (logger.isDebugEnabled()) {
                                logger.debug("Could not resolve target bean for scoped proxy '" + 
                    beanName + "'", ex); } } } try { processBean(beanName, type); } catch (Throwable ex) { throw new BeanInitializationException("Failed to process @EventListener " + "annotation on bean with name '" + beanName + "'", ex); } } } } }

這里主要看processBean(beanName, type) 處理bean

private void processBean(final String beanName, final Class<?> targetType) {
        // 1. 是否包含注解@EventListener
        if (!this.nonAnnotatedClasses.contains(targetType) &&
                AnnotationUtils.isCandidateClass(targetType, EventListener.class) &&
                !isSpringContainerClass(targetType)) {

            Map<Method, EventListener> annotatedMethods = null;
            try {
                // 2. 查找@EventListener注解, 如果有則拿到標注@EventListener的方法
                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");

                // 3. 獲取bean工廠. 這個bean工廠是我們在創世紀的時候注冊的EventListenerFactory
                List<EventListenerFactory> factories = this.eventListenerFactories;
                Assert.state(factories != null, "EventListenerFactory List not initialized");
                // 4. 循環遍歷有注解的方法
                for (Method method : annotatedMethods.keySet()) {
                    for (EventListenerFactory factory : factories) {
                        if (factory.supportsMethod(method)) {
                            Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));

                            //5. 創建事件監聽器 ApplicationListener<?> applicationListener = factory.createApplicationListener(beanName, targetType, methodToUse); if (applicationListener instanceof ApplicationListenerMethodAdapter) {
                                ((ApplicationListenerMethodAdapter) applicationListener).
                        init(context,
this.evaluator); } // 6. 將監聽器注入到多播器中 context.addApplicationListener(applicationListener); break; } } } if (logger.isDebugEnabled()) { logger.debug(annotatedMethods.size() + " @EventListener methods processed on bean '" + beanName + "': " + annotatedMethods); } } } }

1. 首先判斷, 是否包含@EventListener注解

2. 查找@EventListener注解, 如果有則拿到標注@EventListener的方法

3. 獲取bean工廠. 這個bean工廠是我們在創世紀的時候注冊的EventListenerFactory

4. 循環遍歷有注解的方法

5. 創建事件監聽器

6. 將監聽器注入到多播器中

 

 以上就是注解版的監聽器是如何注入到多播器中的. 

五. 怎樣在所有的bean都創建完以后做擴展代碼?

第一種方式, 添加內置的監聽器, 類加載完以后, 調用監聽器

第二種方法. 就是在使用注解方式的時候,  實現SmartInitializingSingleton接口. 然后在bean實例化完成以后, 在調用

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM