2.3 spring5原始碼系列---內建的後置處理器PostProcess載入原始碼

盛開的太陽發表於2020-11-02

本文涉及主題

1. BeanFactoryPostProcessor呼叫過程原始碼剖析

2. 配置類的解析過程原始碼

3. 配置類@Configuration加與不加的區別

4. 重複beanName的覆蓋規則

5. @ComponentScan的解析原理

 


 

一. 研究目標: 解析spring如何載入配置類

我們經常會在一個類上打上@Configuration, @Component, @Bean等. 帶有這些註解的類, 就是我們所說的配置類. 那麼, spring啟動的時候,是如何載入這些配置類的呢?

下面就以此為目的, 分析spring原始碼. 本節的內容是對上一節內容的實戰分析, 同時更加詳細的解讀spring原始碼

2.3 spring5原始碼系列---內建的後置處理器PostProcess載入原始碼

 

 

我們知道, spring啟動的時候做了3件事, 就是上面的三件事. 

第一件事: 呼叫this()自身的無參建構函式. 初始化了BeanDefinitionReader和BeanDefinitionScanner, 同時初始化了很多spring的原始後置處理器, 這些處理器是用來載入bean的

第二件事: 呼叫register(..) 註冊配置類

第三件事: refresh(..) 這裡包含了整個ioc建立bean的全生命週期, 今天重點看invokeBeanFactoryPostProcessors(beanFactory)載入配置類

 

二. 準備工作: 自定義配置類MainConfig

我們先定義好要分析載入的配置類

package com.lxl.www.iocbeanlifecicle;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * 這是一個配置類,
 * 在配置類裡面定義了掃描的包路徑com.lxl.www.iocbeanlifecicle
 * 這是會將這個包下配置了註解的類掃描到ioc容器裡面,成為一個成熟的bean
 */
@Configuration
@ComponentScan(basePackages = {"com.lxl.www.iocbeanlifecicle"})
public class MainConfig {
}

 

這個配置類很簡單, 使用@ComponentScan註解指定了掃描的包. @Configuration指定當前是一個配置類

接下來定義一個main方法, 載入配置類.

 package com.lxl.www.iocbeanlifecicle;


import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MainStarter {
    public static void main(String[] args) {
        // 第一步: 通過AnnotationConfigApplicationContext讀取一個配置類
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
        //context.addBeanFactoryPostProcessor();
        Car car = (Car) context.getBean("car");
        System.out.println(car.getName());
        context.close();
    }
}

 

在main裡, 通過AnnotationConfigurationApplicationContext讀取配置類MainConfig.class.

配置類被傳進來以後, 到底是怎麼被解析的呢? 這就是我們分析的線索

始終不要忘記我們的整體架構圖. 對照這個圖來分析. 思路更清晰. 整體內容講解在這裡: https://www.cnblogs.com/ITPower/p/13677635.html

2.3 spring5原始碼系列---內建的後置處理器PostProcess載入原始碼

 

 

下面, 從入口進入. 我們的入口就是這裡

new AnnotationConfigApplicationContext(MainConfig.class);

 

下面進入AnnotationConfigApplicationContext的構造方法

public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
        // 進入建構函式, 首先呼叫自身的構造方法this();
        // 呼叫自身的構造方法之前, 要先呼叫父類的構造方法
        this();
        // register配置註冊類
        register(componentClasses);
        // ioc容器shua新介面--非常重要
        refresh();
    }

 

三、讀取配置類後置處理器ConfigurationClassPostProcessor

3.1 呼叫this()無參建構函式

public AnnotationConfigApplicationContext() {
        /**
         * 建立了一個Bean定義的讀取器.
         * 完成了spring內部BeanDefinition的註冊(主要是後置處理器)
         * 讀取了很多spring自定義的配置(主要是後置處理器). 這些類都是spring 的原始類(也就是創世紀的類).
         */
        this.reader = new AnnotatedBeanDefinitionReader(this);

        /**
         * 建立BeanDefinition掃描器
         * 可以用來掃描包或者類, 進而轉換為bd
         *
         * Spring預設的掃描包不是這個scanner物件
         * 而是自己new的一個ClassPathBeanDefinitionScanner
         * Spring在執行工程後置處理器ConfigurationClassPostProcessor時, 去掃描包時會new一個ClassPathBeanDefinitionScanner
         *
         * 這裡的scanner僅僅是為了程式設計師可以手動呼叫AnnotationConfigApplicationContext物件的scan方法
         * 通過呼叫context.scan("package name");掃描處理配置類
         * 掃描
         */
        this.scanner = new ClassPathBeanDefinitionScanner(this);
    }

 

在初始化AnnotatedBeanDefinitionReader(this);的時候, 註冊了很多後置處理器

/**
     * Register all relevant annotation post processors in the given registry.
     * @param registry the registry to operate on
     * @param source the configuration source element (already extracted)
     * that this registration was triggered from. May be {@code null}.
     * @return a Set of BeanDefinitionHolders, containing all bean definitions
     * that have actually been registered by this call
     */
    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));
        }

        // 檢查對事件監聽的支援, 如果不包含事件監聽處理器 internalEventListenerProcessor, 就新增一個
        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;
    }

 

我們看到, 註冊了6個原始RootBeanDefinition, 這些bean是spring自己提前定義好的, 他們的載入是整個spring的基礎. 用於解析spring中其他的類

而這一次我們要研究配置類是如何被讀取的, 所以重點關注的是下面這個後置處理器

ConfigurationClassPostProcessor.class

 

這裡還有很多其他的原始類被註冊了, 但我們的目標是分析配置類是如何被讀取的, 所以, 其他的先忽略, 只看ConfigurationClassPostProcessor.

3.2 ConfigurationClassPostProcessor的繼承結構

2.3 spring5原始碼系列---內建的後置處理器PostProcess載入原始碼 

 可以看到ConfigurationClassPostProcessor是同時實現了BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor. 這一點我們需要記住, 後面會使用到

 

2.3 ConfigurationClassPostProcessor是如何被註冊的

// 如果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));
        }

 

首先,構建了一個RootBeanDefinition. 然後呼叫了registerPostProcessor方法, 三個入參分別是

registry: BeanDefinitionRegistry註冊器, 用於註冊BeanDefinition
def: 剛剛構建的RootBeanDefinition
CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME: 構建BeanDefinition使用的beanName是org.springframework.context.annotation.internalConfigurationAnnotationProcessor

然後呼叫registerPostProcessor方法

@Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException {

        Assert.hasText(beanName, "Bean name must not be empty");
        Assert.notNull(beanDefinition, "BeanDefinition must not be null");

        if (beanDefinition instanceof AbstractBeanDefinition) {
            try {
                ((AbstractBeanDefinition) beanDefinition).validate();
            }
            catch (BeanDefinitionValidationException ex) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                        "Validation of bean definition failed", ex);
            }
        }

        // 從BeanDefinition的一級快取BeanDefinitionMap中讀取BeanDefinition物件, 判斷是否已經存在
        BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);

     // 這裡,如果已經存在,說明被重複載入了, 那麼後面載入的會覆蓋前面載入的bean
        if (existingDefinition != null) {
            // 判斷是否允許BeanDefinition重寫
            if (!isAllowBeanDefinitionOverriding()) {
                throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
            }
            else if (existingDefinition.getRole() < beanDefinition.getRole()) {
                // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
                if (logger.isInfoEnabled()) {
                    logger.info("Overriding user-defined bean definition for bean '" + beanName +
                            "' with a framework-generated bean definition: replacing [" +
                            existingDefinition + "] with [" + beanDefinition + "]");
                }
            }
            else if (!beanDefinition.equals(existingDefinition)) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Overriding bean definition for bean '" + beanName +
                            "' with a different definition: replacing [" + existingDefinition +
                            "] with [" + beanDefinition + "]");
                }
            }
            else {
                if (logger.isTraceEnabled()) {
                    logger.trace("Overriding bean definition for bean '" + beanName +
                            "' with an equivalent definition: replacing [" + existingDefinition +
                            "] with [" + beanDefinition + "]");
                }
            }
            // 覆蓋一級快取的bean定義
            this.beanDefinitionMap.put(beanName, beanDefinition);
        }
        else {
            // 處理迴圈引用的問題
            if (hasBeanCreationStarted()) {
                // Cannot modify startup-time collection elements anymore (for stable iteration)
                synchronized (this.beanDefinitionMap) {
                    this.beanDefinitionMap.put(beanName, beanDefinition);
                    List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
                    updatedDefinitions.addAll(this.beanDefinitionNames);
                    updatedDefinitions.add(beanName);
                    this.beanDefinitionNames = updatedDefinitions;
                    removeManualSingletonName(beanName);
                }
            }
            else {
                // Still in startup registration phase
                this.beanDefinitionMap.put(beanName, beanDefinition);
                this.beanDefinitionNames.add(beanName);
                removeManualSingletonName(beanName);
            }
            this.frozenBeanDefinitionNames = null;
        }

        if (existingDefinition != null || containsSingleton(beanName)) {
            resetBeanDefinition(beanName);
        }
        else if (isConfigurationFrozen()) {
            clearByTypeCache();
        }
    }

 

這裡面的關鍵程式碼是標紅的部分, 將ConfigurationClassPostProcessor放入到了beanDefinitionMap裡面

下面的else是處理迴圈引用的問題, 暫時先不要看. 

 3.3 對照整體框架, 我們知道ConfigurationClassPostProcessor被解析成beanDefinition放入到BeanDefinitionMap中了

 2.3 spring5原始碼系列---內建的後置處理器PostProcess載入原始碼

 

3.4 初始化ClassPathBeanDefinitionScanner

在this()構造方法裡, 還初始化了ClassPathBeanDefinitionScanner, 這裡只說一句. 

this.scanner = new ClassPathBeanDefinitionScanner(this);

 

我們在掃描配置類的時候, 確實使用的是ClassPathBeanDefinitionScanner, 但是, 不是this.scanner物件. 而是自己new的一個ClassPathBeanDefinitionScanner.

這裡的scanner僅僅是為了程式設計師可以手動呼叫AnnotationConfigApplicationContext物件的scan方法

通過呼叫context.scan("package name");掃描處理配置類

使用方式如下:

public static void main(String[] args) {
        // 第一步: 通過AnnotationConfigApplicationContext讀取一個配置類
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
        context.scan("package");
        Car car = (Car) context.getBean("car");
        System.out.println(car.getName());
        context.close();
    }

 

2.3 spring5原始碼系列---內建的後置處理器PostProcess載入原始碼

 

到目前為止完成了後置處理器註冊為BeanDefinition

 

備註: 

ConfigurationClassPostProcessor是一個工具類, 這個類的作用是解析配置類.

工具類有了, 那麼還得有主角呀, 那就是我們上面的配置類. 下面看看配置類的載入

 

四. 讀取自定義配置類MainConfig

 註冊配置類,入口自然是這裡了

public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
        // 進入建構函式, 首先呼叫自身的構造方法this();
        // 呼叫自身的構造方法之前, 要先呼叫父類的構造方法
        this();
        // register配置註冊類
        register(componentClasses);
        // ioc容器shua新介面--非常重要
        refresh();
    }

 

跟蹤進去找到doRegisterBean(...)方法

private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,
            @Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
            @Nullable BeanDefinitionCustomizer[] customizers) {

        // 將入參的配置類beanClass構建成AnnotatedGenericBeanDefinition物件
        AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
        if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
            return;
        }

        abd.setInstanceSupplier(supplier);
        // 讀取配置類的後設資料
        ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
        abd.setScope(scopeMetadata.getScopeName());
        String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));

        // 處理主類通用定義註解
        AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
        if (qualifiers != null) {
            for (Class<? extends Annotation> qualifier : qualifiers) {
                if (Primary.class == qualifier) {
                    abd.setPrimary(true);
                }
                else if (Lazy.class == qualifier) {
                    abd.setLazyInit(true);
                }
                else {
                    abd.addQualifier(new AutowireCandidateQualifier(qualifier));
                }
            }
        }
        if (customizers != null) {
            for (BeanDefinitionCustomizer customizer : customizers) {
                customizer.customize(abd);
            }
        }
        // 將MainConfig.java配置類進行解析.放到BeanDefinitionHolder
        BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
        definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
        BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
    }

 

重點就是紅色這句話, 其他可以略過, 因為我們的配置類很簡單, 直接看BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);

我們找到 registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());方法, 進入到DefaultListableBeanFactory檢視方法, 這個方法之前我們已經呼叫過一次

就是在註冊ConfigurationClassPostProcessor的時候, 我們需要將其解析為BeanDefinition然後放到BeanDefinitionMap中, 這裡也是一樣的, 將我們的配置類MainConfig解析成BeanDefinition放入到BeanDefinitionMap中.

 

這裡的程式碼在整個框架中處於什麼位置呢? 將MainConfig解析為BeanDefinition放入到BeanDefinitionMap中

2.3 spring5原始碼系列---內建的後置處理器PostProcess載入原始碼

以上兩步, 一個是將ConfigurationClassPostProcessor配置類後置處理器, 也就是解析配置的工具類, 解析成BeanDefinition放入到BeanDefinitionMap中

另一個是將我們的目標配置類MainConfig載入到記憶體, 組裝成BeanDefinition放入到BeanDefinitionMap中. 

 

到這裡,我們完成了兩步.

2.3 spring5原始碼系列---內建的後置處理器PostProcess載入原始碼

第一步: 準備工具類ConfigurationClassPostProcessor

第二步: 準備配置類MainConfig. 

 

接下倆, 就是要使用工具類來解析配置類MainConfig了

 

五. 呼叫bean工廠的後置處理器invokeBeanFactoryPostProcessors(beanFactory);

public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
        // 進入建構函式, 首先呼叫自身的構造方法this();
        // 呼叫自身的構造方法之前, 要先呼叫父類的構造方法
        this();
        // register配置註冊類
        register(componentClasses);
        // ioc容器重新整理介面--非常重要
        refresh();
    } 

在refresh()中有很多步驟, 我們重點來看invokeBeanFactoryPostProcessors(beanFactory);

 

/**
     * 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();


            // Prepare the bean factory for use in this context.
            //3. 對bean工廠進行填充屬性
            prepareBeanFactory(beanFactory);

            try {
                // Allows post-processing of the bean factory in context subclasses.
                // 4. 留個子類去實現該介面
                postProcessBeanFactory(beanFactory);

                // Invoke factory processors registered as beans in the context.
                /*
                 *
                 * 呼叫bean工廠的後置處理器
                 * 我們之前在Reader的時候讀取了很多創世紀的PostProcessor後置處理器.
                 * 這裡要呼叫bean工廠的後置處理器. 這麼多創世紀的PostProcessor, 只有一個PostProcessor實現了
                 * BeanFactoryPostProcessor. 那個類就是 ConfigurationClassPostProcessor
                 * 前面已經將ConfigurationClassPostProcessor放入到BeanDefinitionMap中了,
                 * 對應的BeanDefinitionName 是 internalConfigurationAnnotationProcessor
                 *
                 *
                 *
                 */
                invokeBeanFactoryPostProcessors(beanFactory);

                // Register bean processors that intercept bean creation.
                // 註冊bean後置處理器
                registerBeanPostProcessors(beanFactory);

                // Initialize message source for this context.
                // 初始化國際化資源處理器
                initMessageSource();

                // Initialize event multicaster for this context.
                // 建立事件多播放器
                initApplicationEventMulticaster();

                // Initialize other special beans in specific context subclasses.
                // 這個方法通用也是留個子類實現的, spring boot也是從這個方法進行啟動
                onRefresh();

                // Check for listener beans and register them.
                // 將事件監聽器註冊到多播放器上
                registerListeners();

                // Instantiate all remaining (non-lazy-init) singletons.
                // 例項化剩餘的單例項bean
                /**
                 * 這個方法就是迴圈遍歷BeanDefinitionMap, 呼叫getBean, 去生產bean
                 */
                finishBeanFactoryInitialization(beanFactory);

                // Last step: publish corresponding event.
                //最後容器重新整理 釋出重新整理時間(spring cloud是從這裡啟動的 )
                finishRefresh();
            }

            ........
    }

 

invokeBeanFactoryPostProcessors(beanFactory);看名字, 呼叫的是Bean工廠的後置處理器, 上面分析了, 初始化的時候初始化了很多spring原生的後置處理器, 這麼多後置處理器, 其實, 只有一個後置處理器實現了BeanFactoryPostProcessor, 它就是ConfigurationClassPostProcessor, 還記得上面的結構圖麼, 拿下來, 再看一遍. 

 2.3 spring5原始碼系列---內建的後置處理器PostProcess載入原始碼

 這裡呼叫的時候, 原生處理器只會呼叫ConfigurationClassPostProcessor

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        /**
         * 獲取兩處儲存BeanFactoryPostProcessor的物件, 傳入供接下來呼叫
         * 1. 當前bean工廠
         * 2. 和我們自己呼叫addBeanFacoryPostProcessor自定義BeanFactoryPostProcessor
         *
         * 引數: getBeanFactoryPostProcessors() 傳了一個工廠的後置處理器的List, 這個時候list是空的
         * getBeanFactoryPostProcessors()裡面的值是怎麼來的呢?
         * 通過在自定義main方法中呼叫context.addBeanFactoryPostProcessor(...);來新增
         *
         * public static void main(String[] args) {
         *         // 第一步: 通過AnnotationConfigApplicationContext讀取一個配置類
         *         AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
         *         context.addBeanFactoryPostProcessor(...);
         *         Car car = (Car) context.getBean("car");
         *         System.out.println(car.getName());
         *         context.close();
         * }
         */
        PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

        // Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
        // (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
        if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
            beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
            beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
        }
    ......
    }

 

這裡要呼叫bean工廠的後置處理器了. 看上面的註釋, 註釋寫的很清晰.

在呼叫PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());的時候呼叫了getBeanFactoryPostProcessors()方法. 

  public List<BeanFactoryPostProcessor> getBeanFactoryPostProcessors() {
       return this.beanFactoryPostProcessors;
   }
getBeanFactoryPostProcessors() 返回的是一個工廠的後置處理器的List, 這個時候list是空的
getBeanFactoryPostProcessors()裡面的值是怎麼來的呢?
通過在自定義main方法中呼叫context.addBeanFactoryPostProcessor(...);來新增. 也就是通過main方法手動新增的beanFactoryPostProcessor. 如下所示
public static void main(String[] args) {
           // 第一步: 通過AnnotationConfigApplicationContext讀取一個配置類
           AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
           context.addBeanFactoryPostProcessor(...);
           Car car = (Car) context.getBean("car");
           System.out.println(car.getName());
           context.close();
    }

 

接下來重點來了. PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()); 方法實現一共分為兩大步:

第一步: 呼叫所有實現了 BeanDefinitionRegistryPostProcessor 介面的bean定義. (BeanDefinitionRegistryPostProcessor帶註冊功能的後置處理器)

第二步: 呼叫BeanFactoryPostProcessor Bean工廠的後置處理器

第一步: 呼叫所有實現了 BeanDefinitionRegistryPostProcessor 介面的bean定義. 

來看看原始碼是如何定義的. 重點看程式碼的註釋, 每一部分的功能都有明確標出, 註釋寫的很詳細

 

public static void invokeBeanFactoryPostProcessors(
            ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

        /**
         * 首先,呼叫BeanDefinitionRegistryPostProcessors的後置處理器
         * 定義已處理的後置處理器
         */
        // Invoke BeanDefinitionRegistryPostProcessors first, if any.
        Set<String> processedBeans = new HashSet<>();

        /**
         * 這裡一共分為兩大步:
         * 第一步: 呼叫所有實現了 BeanDefinitionRegistryPostProcessor 介面的bean定義. (BeanDefinitionRegistryPostProcessor帶註冊功能的後置處理器)
         * 第二步: 呼叫BeanFactoryPostProcessor Bean工廠的後置處理器
         */

        /**********************第一步: 呼叫所有實現了BeanDefinitionRegistryPostProcessor介面的bean定義  begin****************************/
        // 判斷beanFactory是否實現了BeanDefinitionRegistry, 實現了該結構就有註冊和獲取Bean定義的能力
        if (beanFactory instanceof BeanDefinitionRegistry) {
            BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
            List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
            List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();

            for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
                if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
                    BeanDefinitionRegistryPostProcessor registryProcessor =
                            (BeanDefinitionRegistryPostProcessor) postProcessor;
                    registryProcessor.postProcessBeanDefinitionRegistry(registry);
                    registryProcessors.add(registryProcessor);
                }
                else {
                    regularPostProcessors.add(postProcessor);
                }
            }

            // Do not initialize FactoryBeans here: We need to leave all regular beans
            // uninitialized to let the bean factory post-processors apply to them!
            // Separate between BeanDefinitionRegistryPostProcessors that implement
            // PriorityOrdered, Ordered, and the rest.
            /**
             * 這是一個集合, 存馬上即將要被呼叫的BeanDefinitionRegistryPostProcessor
             */
            List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
            // 第一步, 呼叫實現了PriorityOrdered的BeanDefinitionRegistryPostProcessors
            // 在所有創世紀的後置處理器中, 只有 internalConfigurationAnnotationProcessor 實現了 BeanDefinitionRegistryPostProcessors 和 PriorityOrdered
            // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
            String[] postProcessorNames =
                    beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
            for (String ppName : postProcessorNames) {
                // 判斷beanFactory是否實現了PriorityOrdered介面. 如果實現了,是最優先呼叫.
                // 在整個載入過程中,會呼叫四次BeanDefinitionRegistryPostProcessor, 而實現了PriorityOrdered的介面最先呼叫
                if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                    // 呼叫beanFactory.getBean例項化創世界的類ppName
                    currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                    processedBeans.add(ppName);
                }
            }
            sortPostProcessors(currentRegistryProcessors, beanFactory);
            registryProcessors.addAll(currentRegistryProcessors);
            /**
             * 第一次呼叫BeanDefinitionRegistryPostProcessors
             * 在這裡典型的BeanDefinitionRegistryPostProcessors就是ConfigurationClassPostProcessor
             * 用於進行bean定義的載入 比如我們的包掃描 @import 等
             */
            invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
            // 處理完了,清空currentRegistryProcessors
            currentRegistryProcessors.clear();


            // 第二步: 呼叫實現 Ordered 的 BeanDefinitionRegistryPostProcessors。
            // Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
            postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
            for (String ppName : postProcessorNames) {
                // 這時實現了PriorityOrdered.class的postProcessor就不會再被載入進來了, 因為processedBeans.contains(ppName) == true
                if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
                    // 將其放入到currentRegistryProcessors, 馬上就要被呼叫
                    currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                    processedBeans.add(ppName);
                }
            }

            // 對所有的處理器進行排序. 呼叫了Ordered的方法, 會返回排序(一個數字), 然後根據數字排序即可
            sortPostProcessors(currentRegistryProcessors, beanFactory);
            registryProcessors.addAll(currentRegistryProcessors);

            /**
             * 第二次呼叫BeanDefinitionRegistryPostProcessors
             * 在這裡典型的BeanDefinitionRegistryPostProcessors就是ConfigurationClassPostProcessor
             * 用於進行bean定義的載入 比如我們的包掃描 @import 等
             */
            invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
            currentRegistryProcessors.clear();


            // 第三步. 呼叫沒有實現任何優先順序介面的 BeanDefinitionRegistryPostProcessor
            // Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
            boolean reiterate = true;
            while (reiterate) {
                reiterate = false;
                // 獲取
                postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
                for (String ppName : postProcessorNames) {
                    // 已處理過的postProcessor不再處理
                    if (!processedBeans.contains(ppName)) {
                        currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                        processedBeans.add(ppName);
                        reiterate = true;
                    }
                }
                sortPostProcessors(currentRegistryProcessors, beanFactory);
                registryProcessors.addAll(currentRegistryProcessors);
                /**
                 * 第三次呼叫BeanDefinitionRegistryPostProcessors
                 * 在這裡典型的BeanDefinitionRegistryPostProcessors就是ConfigurationClassPostProcessor
                 * 用於進行bean定義的載入 比如我們的包掃描 @import 等
                 */
                invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
                currentRegistryProcessors.clear();
            }

            // Now, invoke the postProcessBeanFactory callback of all processors handled so far.
            /*
             * 第四步:呼叫bean工廠的後置處理器
             * registryProcessors: 帶有註冊功能的bean工廠的後置處理器
             * regularPostProcessors: 不帶註冊功能的bean工廠的後置處理器
             */
            invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
            invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
        }

        else {
            /*
             * 如果當前的beanFactory沒有實現BeanDefinitionRegistry 說明沒有註冊Bean定義的能力
             * 那麼就直接呼叫 BeanDefinitionRegistryPostProcessor.postProcessBeanFactory方法
             */

            // Invoke factory processors registered with the context instance.
            invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
        }

        /**********************第一步: 呼叫所有實現了BeanDefinitionRegistryPostProcessor介面的bean定義  end****************************/

        /**********************第二步: 呼叫BeanFactoryPostProcessor Bean工廠的後置處理器  begin****************************/

        // Do not initialize FactoryBeans here: We need to leave all regular beans
        // uninitialized to let the bean factory post-processors apply to them!
        String[] postProcessorNames =
                beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

        // Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
        // Ordered, and the rest.
        // 優先排序的後置處理器
        List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
        List<String> orderedPostProcessorNames = new ArrayList<>();
        List<String> nonOrderedPostProcessorNames = new ArrayList<>();
        for (String ppName : postProcessorNames) {
            if (processedBeans.contains(ppName)) {
                // skip - already processed in first phase above
            }
            else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
            }
            else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
                orderedPostProcessorNames.add(ppName);
            }
            else {
                nonOrderedPostProcessorNames.add(ppName);
            }
        }

        // 首先, 呼叫有優先順序排序的後置處理器
        // First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
        sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
        invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

        // 第二, 呼叫實現了Ordered排序的後置處理器
        // Next, invoke the BeanFactoryPostProcessors that implement Ordered.
        List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
        for (String postProcessorName : orderedPostProcessorNames) {
            orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
        }
        sortPostProcessors(orderedPostProcessors, beanFactory);
        invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

        // 最後, 呼叫沒有實現任何排序介面的beanFactory後置處理器
        // Finally, invoke all other BeanFactoryPostProcessors.
        List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
        for (String postProcessorName : nonOrderedPostProcessorNames) {
            nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
        }
        invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

        /**********************第二步: 呼叫BeanFactoryPostProcessor Bean工廠的後置處理器  end****************************/
        // Clear cached merged bean definitions since the post-processors might have
        // modified the original metadata, e.g. replacing placeholders in values...
        beanFactory.clearMetadataCache();
    }

 

 

2.3 spring5原始碼系列---內建的後置處理器PostProcess載入原始碼

 

 

 下面我們就來分析上圖所示的內容. 

 1. 對照原始碼和上圖, 我們來看第一次呼叫

        // 第一次, 呼叫實現了PriorityOrdered的BeanDefinitionRegistryPostProcessors
            // 在所有創世紀的後置處理器中, 只有 internalConfigurationAnnotationProcessor 實現了 BeanDefinitionRegistryPostProcessors 和 PriorityOrdered
            // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
            String[] postProcessorNames =
                    beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
            for (String ppName : postProcessorNames) {
                // 判斷beanFactory是否實現了PriorityOrdered介面. 如果實現了,是最優先呼叫.
                // 在整個載入過程中,會呼叫四次BeanDefinitionRegistryPostProcessor, 而實現了PriorityOrdered的介面最先呼叫
                if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                    // 呼叫beanFactory.getBean例項化創世界的類ppName
                    currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                    processedBeans.add(ppName);
                }
            }
            sortPostProcessors(currentRegistryProcessors, beanFactory);
            registryProcessors.addAll(currentRegistryProcessors);
            /**
             * 第一次呼叫BeanDefinitionRegistryPostProcessors
             * 在這裡典型的BeanDefinitionRegistryPostProcessors就是ConfigurationClassPostProcessor
             * 用於進行bean定義的載入 比如我們的包掃描 @import 等
             */
            invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
            // 處理完了,清空currentRegistryProcessors
            currentRegistryProcessors.clear();

 

首先, 拿到了所有實現了BeanDefinitionRegistryPostProcessor的後置處理器, 上面我們做過鋪墊,只有ConfigurationClassPostProcessor實現了BeanDefinitionRegistryPostProcessor後置處理器

所以,這裡過濾出來的postProcessorNames只有一個,就是ConfigurationClassPostProcessor, 接下來, 判斷這個類是否實現了PriorityOrdered 優先排序的介面, 如果實現了, 那麼放入到currentRegistryProcessors中, 後面會進行呼叫.

接下來, 執行invokeBeanDefinitionRegistryPostProcessors

這是第一次呼叫BeanDefinitionRegistryPostProcessors

 

2. 第二次呼叫BeanDefinitionRegistryPostProcessors

        // 第二步: 呼叫實現 Ordered 的 BeanDefinitionRegistryPostProcessors。
            // Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
            postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
            for (String ppName : postProcessorNames) {
                // 這時實現了PriorityOrdered.class的postProcessor就不會再被載入進來了, 因為processedBeans.contains(ppName) == true
                if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
                    // 將其放入到currentRegistryProcessors, 馬上就要被呼叫
                    currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                    processedBeans.add(ppName);
                }
            }

            // 對所有的處理器進行排序. 呼叫了Ordered的方法, 會返回排序(一個數字), 然後根據數字排序即可
            sortPostProcessors(currentRegistryProcessors, beanFactory);
            registryProcessors.addAll(currentRegistryProcessors);

            /**
             * 第二次呼叫BeanDefinitionRegistryPostProcessors
             * 在這裡典型的BeanDefinitionRegistryPostProcessors就是ConfigurationClassPostProcessor
             * 用於進行bean定義的載入 比如我們的包掃描 @import 等
             */
            invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
            currentRegistryProcessors.clear();

 

第二次呼叫的時候 ,依然是獲取所有的實現了BeanDefinitionRegistryPostProcessor介面的後置處理器, 且這個處理器沒有實現過PriorityOrdered也就是沒有被上面呼叫過. 且實現了Ordered介面

這一類新增到currentRegistryProcessors集合中, 然後呼叫invokeBeanDefinitionRegistryPostProcessors處理

這是第二次呼叫BeanDefinitionRegistryPostProcessor

 

3. 第三次呼叫BeanDefinitionRegistryPostProcessor

         // 第三步. 呼叫沒有實現任何優先順序介面的 BeanDefinitionRegistryPostProcessor
            // Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
            boolean reiterate = true;
            while (reiterate) {
                reiterate = false;
                // 獲取
                postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
                for (String ppName : postProcessorNames) {
                    // 已處理過的postProcessor不再處理
                    if (!processedBeans.contains(ppName)) {
                        currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                        processedBeans.add(ppName);
                        reiterate = true;
                    }
                }
                sortPostProcessors(currentRegistryProcessors, beanFactory);
                registryProcessors.addAll(currentRegistryProcessors);
                /**
                 * 第三次呼叫BeanDefinitionRegistryPostProcessors
                 * 在這裡典型的BeanDefinitionRegistryPostProcessors就是ConfigurationClassPostProcessor
                 * 用於進行bean定義的載入 比如我們的包掃描 @import 等
                 */
                invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
                currentRegistryProcessors.clear();
            }

 

第三次呼叫的是沒有實現過任何排序介面的後置處理器. 並將其放入到currentRegistryProcessors, 然後執行invokeBeanDefinitionRegistryPostProcessors

 

 

4. 第四次呼叫

// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
/*
 * 呼叫bean工廠的後置處理器
 * registryProcessors: 帶有註冊功能的bean工廠的後置處理器
 * regularPostProcessors: 不帶註冊功能的bean工廠的後置處理器
 */
// 呼叫BeanDefinitionRegistryPostProcessor.postProcessBeanFactory方法----為什麼是呼叫BeanDefinitionRegistryPostProcessor? 因為
// ConfigurationClassPostProcessor 實現了 BeanDefinitionRegistryPostProcessor 和 BeanFactoryPostProcessors
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
// 呼叫BeanFactoryPostProcessor 自設的(ConfigurationClassPostProcessor沒有)
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);

 

ConfigurationClassPostProcessor同時實現了BeanDefinitionRegistryPostProcessor 和 BeanFactoryPostProcessors, 呼叫的是invokeBeanFactoryPostProcessors

 

一共進行了4次呼叫

總結: 優先處理的是實現了PriorityOrdered的後置處理器, 然後呼叫實現了Order介面的後置處理器, 最後呼叫了沒有實現任何排序方法的後置處理器. 最後呼叫工廠類方法.

 

下面我們來具體分析invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);

 

5. 提問: 檢驗一下是否理解了上面四個步驟 

 

1. ConfigurationClassPostProcessor會呼叫1234哪幾步?

因為ConfigurationClassPostProcessor實現了BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor,PriorityOrdered, 因此會呼叫1,4

2. 如果自己定義了一個MyBeanFactoryPostProcessor會呼叫1234那幾步?

package com.lxl.www.iocbeanlifecicle;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.stereotype.Component;

@Component
public class MyBeanFactoryPostProcessor implements BeanDefinitionRegistryPostProcessor {
   @Override
   public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
      
   }

   @Override
   public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

   }
}


因為MyBeanFactoryPostProcessor是自定義的, 沒有實現任何PriorityOrdered 或者 Order, 因此, 會呼叫3,4

 

二. 詳細研究第四步, invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);的邏輯.

我們在這一步打個斷點, 然後跟著斷點一步一步點選進去

 

 

 這是registryProcessors裡面只有一個後置處理器, 就是ConfigurationClassPostProcessor. 

然後進入到ConfigurationClassPostProcessor.postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)方法

@Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        int factoryId = System.identityHashCode(beanFactory);
        if (this.factoriesPostProcessed.contains(factoryId)) {
            throw new IllegalStateException(
                    "postProcessBeanFactory already called on this post-processor against " + beanFactory);
        }
        this.factoriesPostProcessed.add(factoryId);
        if (!this.registriesPostProcessed.contains(factoryId)) {
            // BeanDefinitionRegistryPostProcessor hook apparently not supported...
            // Simply call processConfigurationClasses lazily at this point then.
            processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
        }

        // 使用 cglib 配置類進行代理, 因為@Bean方法到時候要進行建立Bean的例項.
        enhanceConfigurationClasses(beanFactory);
        beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
    }

 

這裡先看enhanceConfigurationClasses(beanFactory);個方法 

public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
        Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();

        for (String beanName : beanFactory.getBeanDefinitionNames()) {
            BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
            Object configClassAttr = beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE);
            MethodMetadata methodMetadata = null;
            if (beanDef instanceof AnnotatedBeanDefinition) {
                methodMetadata = ((AnnotatedBeanDefinition) beanDef).getFactoryMethodMetadata();
            }
            if ((configClassAttr != null || methodMetadata != null) && beanDef instanceof AbstractBeanDefinition) {
                // Configuration class (full or lite) or a configuration-derived @Bean method
                // -> resolve bean class at this point...
                AbstractBeanDefinition abd = (AbstractBeanDefinition) beanDef;
                if (!abd.hasBeanClass()) {
                    try {
                        abd.resolveBeanClass(this.beanClassLoader);
                    }
                    catch (Throwable ex) {
                        throw new IllegalStateException(
                                "Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
                    }
                }
            }

            /**
             * 只有full版配置才會建立cglib代理
             * full是怎麼來的呢? 我們使用@Configuration註解了, 在載入的時候, 就會設定為full
             * 當設定為full以後, 我們在呼叫的時候, 就會建立一個cglib動態代理.
             *
             * 為什麼要建立動態代理呢?
             * 動態代理可以保證, 每次建立的bean物件只有一個
             *
             * 那麼加@Configuration和不加本質上的區別是什麼?
             * 當在配置類中一個@Bean使用方法的方式引入另一個Bean的時候, 如果不加@Configuration註解, 就會重複載入Bean
             * 如果加了@Configuration, 則會在這裡建立一個cglib代理, 當呼叫了@Bean方法是會先檢測容器中是否存在這個Bean, 如果不存在則建立, 存在則直接使用.
             */
            if (ConfigurationClassUtils.CONFIGURATION_CLASS_FULL.equals(configClassAttr)) {
                if (!(beanDef instanceof AbstractBeanDefinition)) {
                    throw new BeanDefinitionStoreException("Cannot enhance @Configuration bean definition '" +
                            beanName + "' since it is not stored in an AbstractBeanDefinition subclass");
                }
                else if (logger.isInfoEnabled() && beanFactory.containsSingleton(beanName)) {
                    logger.info("Cannot enhance @Configuration bean definition '" + beanName +
                            "' since its singleton instance has been created too early. The typical cause " +
                            "is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor " +
                            "return type: Consider declaring such methods as 'static'.");
                }
                configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
            }
        }
        if (configBeanDefs.isEmpty()) {
            // nothing to enhance -> return immediately
            return;
        }

        ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
        for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {
            AbstractBeanDefinition beanDef = entry.getValue();
            // If a @Configuration class gets proxied, always proxy the target class
            beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
            // Set enhanced subclass of the user-specified bean class
            Class<?> configClass = beanDef.getBeanClass();
            Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
            if (configClass != enhancedClass) {
                if (logger.isTraceEnabled()) {
                    logger.trace(String.format("Replacing bean definition '%s' existing class '%s' with " +
                            "enhanced class '%s'", entry.getKey(), configClass.getName(), enhancedClass.getName()));
                }
                beanDef.setBeanClass(enhancedClass);
            }
        }
    }

 

粗體部分就是判斷是否需要進行cglib代理. 進行cglib代理的條件是, beanDefinition中屬性configurationClass的值是full. 只有full版配置才會建立cglib代理

那麼有下面幾個問題: 

問題1: full版本配置是什麼呢?

我們使用@Configuration註解了, 在載入的時候, 就會將configurationClass屬性設定為full.當設定為full以後, 我們在呼叫的時候, 就會建立一個cglib動態代理.

問題2: 為什麼要建立動態代理呢?

動態代理可以保證, 每次建立的bean物件只有一個

問題3:那麼加@Configuration和不加本質上的區別是什麼?

當在配置類中一個@Bean使用方法的方式引入另一個Bean的時候, 如果不加@Configuration註解, 就會重複載入Bean.如果加了@Configuration, 則會在這裡建立一個cglib代理, 當呼叫了@Bean方法是會先檢測容器中是否存在這個Bean, 如果不存在則建立, 存在則直接使用.

問題4:full是怎麼來的呢?

這是在上面呼叫invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);介面的時候, 標記的是full還是Lite

下面來看一下原始碼

2.3 spring5原始碼系列---內建的後置處理器PostProcess載入原始碼

 

 在這裡一步,執行的時候,進行了這個類是full的還是lite,繼續忘下看

2.3 spring5原始碼系列---內建的後置處理器PostProcess載入原始碼

 

 此時滿足條件的postProcessor只有一個, 那就是ConfigurationClassPostProcessor. 下面直接看ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry()方法

2.3 spring5原始碼系列---內建的後置處理器PostProcess載入原始碼

 

 前面都是一些條件判斷, 重點看processConfigBeanDefinitions(registry);

2.3 spring5原始碼系列---內建的後置處理器PostProcess載入原始碼

 

 在這裡,這個方法判斷了, 這個類是full的還是lite的. 下面直接上程式碼

/**
     * Check whether the given bean definition is a candidate for a configuration class
     * (or a nested component class declared within a configuration/component class,
     * to be auto-registered as well), and mark it accordingly.
     * @param beanDef the bean definition to check
     * @param metadataReaderFactory the current factory in use by the caller
     * @return whether the candidate qualifies as (any kind of) configuration class
     */
    public static boolean checkConfigurationClassCandidate(
            BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {

        String className = beanDef.getBeanClassName();
        if (className == null || beanDef.getFactoryMethodName() != null) {
            return false;
        }

        AnnotationMetadata metadata;
        // 獲取後設資料
        if (beanDef instanceof AnnotatedBeanDefinition &&
                className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {
            // Can reuse the pre-parsed metadata from the given BeanDefinition...
            metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
        }
        else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {
            // Check already loaded Class if present...
            // since we possibly can't even load the class file for this Class.
            Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
            if (BeanFactoryPostProcessor.class.isAssignableFrom(beanClass) ||
                    BeanPostProcessor.class.isAssignableFrom(beanClass) ||
                    AopInfrastructureBean.class.isAssignableFrom(beanClass) ||
                    EventListenerFactory.class.isAssignableFrom(beanClass)) {
                return false;
            }
            metadata = AnnotationMetadata.introspect(beanClass);
        }
        else {
            try {
                MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className);
                metadata = metadataReader.getAnnotationMetadata();
            }
            catch (IOException ex) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Could not find class file for introspecting configuration annotations: " +
                            className, ex);
                }
                return false;
            }
        }

        // 判斷後設資料中是否包含Configuration註解
        Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
        /**
         * 判斷, proxyBeanMethods屬性是否為true, 如果為true就是一個完全的類,
         * 也就是帶有@Configuration註解, 設定Configuration_class屬性為full
         *
         * proxyBeanMethods配置類是用來指定@Bean註解標註的方法是否使用代理,
         * 預設是true使用代理,直接從IOC容器之中取得物件;
         * 如果設定為false,也就是不使用註解,每次呼叫@Bean標註的方法獲取到的物件和IOC容器中的都不一樣,是一個新的物件,所以我們可以將此屬性設定為false來提高效能。
         */
        if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
            beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
        }
        // 判斷是不是帶了@Component, @ComponentScan @Import @ImportResource @Bean註解,
        // 如果帶有這幾種註解, 就將其Configuration_class屬性為lite型別的配置類
        else if (config != null || isConfigurationCandidate(metadata)) {
            beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
        }
        else {
            return false;
        }

        // It's a full or lite configuration candidate... Let's determine the order value, if any.
        Integer order = getOrder(metadata);
        if (order != null) {
            beanDef.setAttribute(ORDER_ATTRIBUTE, order);
        }

        return true;
    }

 

上面主要是獲取後設資料, 然後判斷後設資料中是否有Configuration註解. 如果有,返回其屬性. 我們判斷其屬性中proxyBeanMethods是否true, 如果是true, 那麼將其設定為full. 

如果配置中帶有@Component, @ComponentScan @Import @ImportResource @Bean這幾種屬性之一, 那麼就將其設定為lite.

 

問題5: cglib動態代理做了什麼事情呢?

不看原始碼的情況下, 簡單可以理解為, 去ioc工廠裡面通過getBean("car") 查詢了看ioc中是否有這個物件, 如果有就取出來, 不再另建立. 

這也是@Configuration 和其他註解類似@Component和@ComponentScan的本質區別:

當在配置類中一個@Bean使用方法的方式引入另一個Bean的時候, 如果不加@Configuration註解, 就會重複建立Bean

如果加了@Configuration, 則會在這裡建立一個cglib代理, 當呼叫了@Bean方法是會先檢測容器中是否存在這個Bean, 如果不存在則建立, 存在則直接使用.

 

下面來看個例子

基礎類:
public class Car  {
    private String name;
    private Tank tank;

    public String getName() {
        return name;
    }

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

    public Tank getTank() {
        return tank;
    }

    public void setTank(Tank tank) {
        this.tank = tank;
    }
}

public class Tank {
    private String name;

    public Tank() {
        System.out.println("建立一個tank");
    }

    public String getName() {
        return name;
    }

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

}

 

這是定義的car和tank的基礎類

@Configuration
@ComponentScan(basePackages = {"com.lxl.www.iocbeanlifecicle"})
public class MainConfig {

    @Bean("car")
    public Car car() {
        Car car = new Car();
        car.setName("zhangsan");
        // 這裡呼叫了Tank類, tank是通過@Bean註解注入的. 
        car.setTank(tank());
        return car;
    }

    @Bean
    public Tank tank() {
        return new Tank();
    }
}

 

當配置類使用了@Configuration註解的時候, 執行main方法

public class MainStarter {
    public static void main(String[] args) {
        // 第一步: 通過AnnotationConfigApplicationContext讀取一個配置類
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
        context.scan("package");
        //context.addBeanFactoryPostProcessor();
        Car car = (Car) context.getBean("car");
        Car car2 = (Car) context.getBean("car");
        System.out.println(car.getName());
        context.close();
    }
}

 

 

當去掉@Configuration註解的時候, 再次執行, 我們看到建立了兩次tank

//@Configuration
@ComponentScan(basePackages = {"com.lxl.www.iocbeanlifecicle"})
public class MainConfig {

    @Bean("car")
    public Car car() {
        Car car = new Car();
        car.setName("zhangsan");
        // 這裡呼叫了Tank類, tank是通過@Bean註解注入的. 
        car.setTank(tank());
        return car;
    }

    @Bean
    public Tank tank() {
        return new Tank();
    }
}

 

 

在main方法中呼叫了兩次(Car) context.getBean("car");

在new一個物件的時候, 如果不取ioc容器中取, 那麼每一次都會建立一個新的.

在ioc容器中, car物件只有一個, 但是在構建car的時候, 呼叫了tank, tank在ioc容器中卻不一定只有一份. 只有使用了@Configuration, 表示需要使用cglib動態代理查詢tank類, 保證ioc容器中只有一份.

 

 

7. 詳細研究四次呼叫中的第一次呼叫.  通過分析跟蹤@ComponentScan註解是如何解析的,

通過跟蹤@ComponentScan註解是如何解析的, 分來理解BeanDefinitionScan, BeanDefinitionRegistry, BeanDefinitionReader是如何工作的. 

 

public static void invokeBeanFactoryPostProcessors(
            ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

        /**
         * 首先,呼叫BeanDefinitionRegistryPostProcessors 的後置處理器
         * 定義已處理的後置處理器
         */
        // Invoke BeanDefinitionRegistryPostProcessors first, if any.
        Set<String> processedBeans = new HashSet<>();

        /**
         * 這裡一共分為兩大步:
         * 第一步: 呼叫所有實現了 BeanDefinitionRegistryPostProcessor 介面的bean定義. (BeanDefinitionRegistryPostProcessor帶註冊功能的後置處理器)
         * 第二步: 呼叫BeanFactoryPostProcessor Bean工廠的後置處理器
         */

        /**********************第一步: 呼叫所有實現了BeanDefinitionRegistryPostProcessor介面的bean定義  begin****************************/
        // 判斷beanFactory是否實現了BeanDefinitionRegistry, 實現了該結構就有註冊和獲取Bean定義的能力
        if (beanFactory instanceof BeanDefinitionRegistry) {
            BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
            List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
            List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();

            for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
                if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
                    BeanDefinitionRegistryPostProcessor registryProcessor =
                            (BeanDefinitionRegistryPostProcessor) postProcessor;
                    registryProcessor.postProcessBeanDefinitionRegistry(registry);
                    registryProcessors.add(registryProcessor);
                }
                else {
                    regularPostProcessors.add(postProcessor);
                }
            }

            // Do not initialize FactoryBeans here: We need to leave all regular beans
            // uninitialized to let the bean factory post-processors apply to them!
            // Separate between BeanDefinitionRegistryPostProcessors that implement
            // PriorityOrdered, Ordered, and the rest.
            /**
             * 這是一個集合, 存馬上即將要被呼叫的BeanDefinitionRegistryPostProcessor
             */
            List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
            // 首先, 呼叫實現了PriorityOrdered的BeanDefinitionRegistryPostProcessors
            // 在所有創世紀的後置處理器中, 只有 internalConfigurationAnnotationProcessor 實現了 BeanDefinitionRegistryPostProcessors 和 PriorityOrdered
            // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
            String[] postProcessorNames =
                    beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
            for (String ppName : postProcessorNames) {
                // 判斷beanFactory是否實現了PriorityOrdered介面. 如果實現了,是最優先呼叫.
                // 在整個載入過程中,會呼叫四次BeanDefinitionRegistryPostProcessor, 而實現了PriorityOrdered的介面最先呼叫
                if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                    // 呼叫beanFactory.getBean例項化配置類的後置處理器(創世界的類ppName), 也就是初始化, 例項化, 賦值屬性.
                    currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                    processedBeans.add(ppName);
                }
            }
            sortPostProcessors(currentRegistryProcessors, beanFactory);
            registryProcessors.addAll(currentRegistryProcessors);
            /**
             * 第一次呼叫BeanDefinitionRegistryPostProcessors
             * 在這裡典型的BeanDefinitionRegistryPostProcessors就是ConfigurationClassPostProcessor
             * 用於進行bean定義的載入 比如我們的包掃描 @import 等
             */
            invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
            // 處理完了,清空currentRegistryProcessors
            currentRegistryProcessors.clear();

這裡也有兩大步

第一步: 初始化bean工廠的後置處理器

  通過呼叫beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class) 初始化了bean工廠的後置處理器,

第二步: 解析配置

   呼叫invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);呼叫beanDefinitionRegistry的後置處理器. 篩選出符合條件的配置類. 

2.3 spring5原始碼系列---內建的後置處理器PostProcess載入原始碼

 

如上圖所示, 最後篩選出的配置類只有MainConfig配置類. 也就是說configCandidates配置候選集合中只有一個MainConfig

      // 建立一個ConfigurationClassParser物件, 解析@Configuration class
        ConfigurationClassParser parser = new ConfigurationClassParser(
                this.metadataReaderFactory, this.problemReporter, this.environment,
                this.resourceLoader, this.componentScanBeanNameGenerator, registry);

        Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
        Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
        do {
            // 執行解析
            parser.parse(candidates);
            parser.validate();

 

然後, 接下來建立了一個物件ConfigurationClassParser, 這是一個配置類解析器. 下面將使用這個解析器解析配置類.

重點是如何解析的, 程式碼已重點標註出來了.

 // 執行解析
parser.parse(candidates);

我們這裡是通過註解解析的, 所以直接看下面的程式碼

public void parse(Set<BeanDefinitionHolder> configCandidates) {
        // 迴圈配置類
        for (BeanDefinitionHolder holder : configCandidates) {
            BeanDefinition bd = holder.getBeanDefinition();
            try {
                // 真正的解析bean定義:通過註解後設資料解析
                if (bd instanceof AnnotatedBeanDefinition) {
                    parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
                }
......
}

 

解析主要做了幾件事呢?如下圖:

2.3 spring5原始碼系列---內建的後置處理器PostProcess載入原始碼

 

 解析配置類, 看看配置類是否含有如上標記的註解, 如果有, 則呼叫響應的返回對其進行解析,處理.

下面來看看原始碼. 是如何處理這一塊的.

/**
     * 在這裡會解析@Component  @PropertySources @ComponentScan @ImportResource
     * @param configClass
     * @param sourceClass
     * @param filter
     * @return
     * @throws IOException
     */
    @Nullable
    protected final SourceClass doProcessConfigurationClass(
            ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
            throws IOException {

        // 1. 處理@Component註解,判斷後設資料是否帶有Component註解
        if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
            // Recursively process any member (nested) classes first
            processMemberClasses(configClass, sourceClass, filter);
        }

        // Process any @PropertySource annotations
        // 2. 處理@PropertySource 註解, 判斷後設資料是否帶有@PropertySource註解
        for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
                sourceClass.getMetadata(), PropertySources.class,
                org.springframework.context.annotation.PropertySource.class)) {
            if (this.environment instanceof ConfigurableEnvironment) {
                processPropertySource(propertySource);
            }
            else {
                logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
                        "]. Reason: Environment must implement ConfigurableEnvironment");
            }
        }

        // Process any @ComponentScan annotations
        // 3. 處理@ComponentScan註解, 判斷後設資料是否帶有@ComponentScan註解
        /**
         * 這裡mainConfig配置類中有兩個註解,一個是@Configuration ,一個是@ComponentScan. 在這裡, 我們看一下@ComponentScan
         */
        //componentScans 拿到的就是ComponentScan註解裡的屬性
        Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
                sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
        if (!componentScans.isEmpty() &&
                !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
            for (AnnotationAttributes componentScan : componentScans) {
                // The config class is annotated with @ComponentScan -> perform the scan immediately
                // 解析掃描出來的類, 將其解析為BeanDefinitionHolder物件, 並放入到scannedBeanDefinitions中
                // 這正的解析ComponentScans和ComponentScan中的配置
                Set<BeanDefinitionHolder> scannedBeanDefinitions =
                        this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
                // 迴圈處理包掃描出來的bean定義
                // Check the set of scanned definitions for any further config classes and parse recursively if needed
                for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
                    BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
                    if (bdCand == null) {
                        bdCand = holder.getBeanDefinition();
                    }
                    // 判斷當前掃描出來的是不是一個配置類, 如果是的話, 直接進行遞迴解析.
                    if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
                        parse(bdCand.getBeanClassName(), holder.getBeanName());
                    }
                }
            }
        }

        // 4. 處理@Import註解
        // Process any @Import annotations
        processImports(configClass, sourceClass, getImports(sourceClass), filter, true);

        // 5. 處理@ImportResource註解
        // Process any @ImportResource annotations
        AnnotationAttributes importResource =
                AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
        if (importResource != null) {
            String[] resources = importResource.getStringArray("locations");
            Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
            for (String resource : resources) {
                String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
                configClass.addImportedResource(resolvedResource, readerClass);
            }
        }

        // 6. 處理@Bean註解
        // Process individual @Bean methods
        Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
        for (MethodMetadata methodMetadata : beanMethods) {
            configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
        }

        // 處理預設方法
        // Process default methods on interfaces
        processInterfaces(configClass, sourceClass);

        // 處理超類
        // Process superclass, if any
        if (sourceClass.getMetadata().hasSuperClass()) {
            String superclass = sourceClass.getMetadata().getSuperClassName();
            if (superclass != null && !superclass.startsWith("java") &&
                    !this.knownSuperclasses.containsKey(superclass)) {
                this.knownSuperclasses.put(superclass, configClass);
                // Superclass found, return its annotation metadata and recurse
                return sourceClass.getSuperClass();
            }
        }

        // No superclass -> processing is complete
        return null;
    }

 

下面我們重點看對@ComponentScan和@ComponentScans註解的解析, 為什麼看他呢? 因為很多註解都標記了@Component註解. 

比如@Service註解,本身使用@Component

2.3 spring5原始碼系列---內建的後置處理器PostProcess載入原始碼

 

 再來看@Controller註解, 其實質也是一個@Component註解

2.3 spring5原始碼系列---內建的後置處理器PostProcess載入原始碼

 

 我們在自定義配置類的時候, 會使用@ComponentScan註解. 並傳遞一個包, 作為掃描包. 如MainConfig配置

2.3 spring5原始碼系列---內建的後置處理器PostProcess載入原始碼

 

 這就會掃描包下所有的配置類. 

它主要的邏輯如下:

2.3 spring5原始碼系列---內建的後置處理器PostProcess載入原始碼

 

 在拿到@ComponentScan註解以後, 會對其進行parse. 主要解析裡面的註解. 並對每一個註解進行處理. 處理後將其新增到scanner屬性中. 最後呼叫scanner.doScan(....)方法.

原始碼如下:

// 解析配置
    public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
        // 定義了一個類路徑掃描器ClassPathBeanDefinitionScanner
        // 這裡的scanner用於讀取配置類
        ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
                componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);

        // 1. 判斷是否有nameGenerator註解
        // 為掃描器設定beanName的生成器物件, 並賦值給scanner, BeanNameGenerator的作用是為bean definitions生成Bean名字的介面
        Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
        boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
        scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :
                BeanUtils.instantiateClass(generatorClass));

        // 2. 判斷是否有scopedProxy註解
        ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy");
        if (scopedProxyMode != ScopedProxyMode.DEFAULT) {
            scanner.setScopedProxyMode(scopedProxyMode);
        }
        else {
            Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver");
            scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));
        }

        scanner.setResourcePattern(componentScan.getString("resourcePattern"));

        // 3. 判斷屬性中是否有includeFilters屬性, 有的話就新增到scanner中
        // 設定componentScan中包含的過濾器 -- 在使用註解的時候配置了包含和排除的過濾器, 這裡進行處理
        for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {
            for (TypeFilter typeFilter : typeFiltersFor(filter)) {
                scanner.addIncludeFilter(typeFilter);
            }
        }

        // 4. 判斷屬性總是否有excludeFilters屬性, 有的話放到scnanner中
        // 設定componentScan中排除的過濾器
        for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {
            for (TypeFilter typeFilter : typeFiltersFor(filter)) {
                scanner.addExcludeFilter(typeFilter);
            }
        }

        // 5. 判斷是否有lazyInit屬性
        // 獲取配置類中懶載入初始化的屬性
        boolean lazyInit = componentScan.getBoolean("lazyInit");
        if (lazyInit) {
            scanner.getBeanDefinitionDefaults().setLazyInit(true);
        }

        Set<String> basePackages = new LinkedHashSet<>();

        // 6. 判斷是否有basePackages屬性
        // 獲取basePackages屬性, 也就是我們定義的包掃描路徑
        String[] basePackagesArray = componentScan.getStringArray("basePackages");
        for (String pkg : basePackagesArray) {
            String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),
                    ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
            Collections.addAll(basePackages, tokenized);
        }
        for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {
            basePackages.add(ClassUtils.getPackageName(clazz));
        }
        if (basePackages.isEmpty()) {
            basePackages.add(ClassUtils.getPackageName(declaringClass));
        }

        scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
            @Override
            protected boolean matchClassName(String className) {
                return declaringClass.equals(className);
            }
        });

        // 呼叫scanner.doScan()方法, 掃描basePackages包
        return scanner.doScan(StringUtils.toStringArray(basePackages));
    }

 

呼叫doScan方法掃描配置類. 我們來看看主要做了哪些事情

2.3 spring5原始碼系列---內建的後置處理器PostProcess載入原始碼

 

 

 第一步: 找到所有候選的BeanDefinition.

  上面解析出了@ComponentScan註解傳遞過來的basePackages包. 掃描包中所有的類, 得到候選類. 

  掃描的時候做了幾件事呢? 看最上圖最右側部分. 這掃描出來就是我們的目標類.

 第二步: 解析這些準目標類. 

第三步: 設定預設的beanDefinition屬性

/**
     * 設定預設的bean定義的資訊
     * Apply the provided default values to this bean.
     * @param defaults the default settings to apply
     * @since 2.5
     */
    public void applyDefaults(BeanDefinitionDefaults defaults) {
        // 設定這個類是不是懶載入的
        Boolean lazyInit = defaults.getLazyInit();
        if (lazyInit != null) {
            setLazyInit(lazyInit);
        }
        // 設定預設的自動裝配方式
        setAutowireMode(defaults.getAutowireMode());
        setDependencyCheck(defaults.getDependencyCheck());
        // 設定初始化方法的名稱
        setInitMethodName(defaults.getInitMethodName());
        // 是否可以呼叫InitMethod方法
        setEnforceInitMethod(false);
        setDestroyMethodName(defaults.getDestroyMethodName());
        // 是否可以呼叫DestroyMethod方法
        setEnforceDestroyMethod(false);
    }

 

 第四步: 將解析出來的bean定義註冊到ioc容器中

 這裡就呼叫了BeanDefinitionReaderUtils.registerBeanDefinition註冊bean定義. 之前註冊過配置類, 這裡和其是一樣的. 所以不再贅述了

 

到此為止, 就將MainConfig配置類解析完並註冊到ioc容器中了.

 

相關文章