2.2 spring5原始碼 -- ioc載入的整體流程

盛開的太陽發表於2020-09-24

之前我們知道了spring ioc的載入過程, 具體如下圖. 下面我們就來對照下圖, 看看ioc載入的原始碼.

2.2 spring5原始碼 -- ioc載入的整體流程

 下面在用裝修類比, 看看個個元件都是怎麼工作的.

2.2 spring5原始碼 -- ioc載入的整體流程

 

接下來是原始碼分析的整體結構圖. 對照上面的思路梳理出來的

2.2 spring5原始碼 -- ioc載入的整體流程

 

一、原始碼分析的入口 

通常,我們的入口都是從main方法進入. 這裡我們也來定義一個main方法

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

 

順便再來看看還有哪些相關的類

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

這個類有一個註解@Configuration, 這樣這個類會被掃描成bean

還有一個註解@ComponentScan(backPackage = {"com.lxl.www.iocbeanlifecicle"}) 他表示, 請掃描com.lxl.www.iocbeanlifecicle包下所有的類.

com.lxl.www.iocbeanlifecicle 這個包下還有哪些類呢? 我們來看看專案結構

2.2 spring5原始碼 -- ioc載入的整體流程

 

 

 這是這個包下完整的專案結構. 

下面會逐漸說明, 每個類的用途

 

二. 最重要的類BeanFactory

我們知道在將一個class載入為bean的過程中BeanFactory是最最重要的, 那麼他是何時被載入的呢?

我們來跟蹤一下帶有一個引數的構造方法AnnotationConfigApplicationContext

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

這就是AnnotationConfigApplicationContext初始化的時候做的三件事

第一件事:  this();  //呼叫自身的無參構造方法. 同時呼叫父類的構造方法

第二件事: register(componentClasses); // 呼叫註冊器, 這裡會載入兩個BeanDefinitionReader和BeanDefinitionScanner. 這兩位的角色是什麼呢? 可以回憶一下之前的框架圖

第三件事: refresh();  // 這是ioc容器重新整理, 非常重要. 無論是spring boot還是spring mvc都有這個方法. 這個方法包含了整個spring ioc載入的全生命流程. 也是我們要重點學習的方法

 

下面來看看BeanFactory是何時被載入進來的呢?

在初始化方法的時候呼叫了自身的無參建構函式, 在呼叫自身無參建構函式的時候, 同時會呼叫父類的無參建構函式. 

public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {
  ......
}

父類是GenericApplicationContext, 其無參建構函式就做了一件事

   public GenericApplicationContext() {
        // 構造了一個BeanFactory.
        // 在呼叫GenericApplicationContext父類建構函式, 為ApplicationContext spring上下文物件初始化beanFactory
        // 為什麼初始化的是DefaultListableBeanFactory呢?
        // 我們在看BeanFactory介面的時候發現DefaultListableBeanFactory是最底層的實現, 功能是最全的.
        // 檢視
        this.beanFactory = new DefaultListableBeanFactory();
    }    

初始化DefaultListableBeanFactory. 

問題: BeanFactory有很多, 為什麼初始化的時候選擇DefaultListableBeanFactory呢?

我們來看看DefaultListableBeanFactory的結構. 快捷鍵option + command + u --> Java Class Diagrams

2.2 spring5原始碼 -- ioc載入的整體流程

 

 

 通過觀察, 我們發現, DefaultListableBeanFactory實現了各種各樣的BeanFactory介面, 同時還是先了BeanDefinitionRegistry介面. 

也就是說, DefaultListableBeanFactory不僅僅有BeanFactory的能力, 同時還有BeanDefinitionRegistry的能力. 它的功能是最全的.

所以, 我們使用的是一個功能非常強大的類Bean工廠類. 

 

AnnotationConfigApplicationContext繼承了GenericApplicationContext,

而 GenericApplicationContext 實現了AnnotationConfigRegistry介面.

所以AnnotationConfigApplicationContext有AnnotationConfigRegistry的能力.

 

三. bean定義讀取器AnnotatedBeanDefinitionReader

接著上面, 第一步呼叫的是this(). 也就是AnnotationConfigApplicationContext的無參建構函式. 在這個無參建構函式裡一共做了兩件事情

    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);
    }

1. 初始化AnnotatedBeanDefinitionReader.

2. 初始化ClassPathBeanDefinitionScanner

我們先來看看AnnotatedBeanDefinitionReader

2.2 spring5原始碼 -- ioc載入的整體流程

 

 

 在這裡的描述中, 我們知道BeanDefinitionReader是要去掃描配置或者註解, 如果理解為銷售的話, 就是掃描樓盤. 這裡面就有我們的潛在使用者. 也就是我們需要將其轉換為bean的物件. 

那麼初始化的時候,AnnotatedBeanDefinitionReader做了什麼呢?

重點看這句

    public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
        Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
        Assert.notNull(environment, "Environment must not be null");
        this.registry = registry;
        this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
     // 註冊註解型別配置的處理器 AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry); }

註冊註解型別配置的處理器

AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);

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

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

        // 2. 如果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.
        // 3. 檢查對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.
        // 4. 檢查對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));
        }

        // 5. 檢查對事件監聽的支援, 如果不包含事件監聽處理器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));
        }

        // 6. 如果不包含事件監聽工廠處理器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個後置處理器.

 2.2 spring5原始碼 -- ioc載入的整體流程

 

 

四. bean定義掃描器ClassPathBeanDefinitionScanner

 

  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);
    }

主要看加粗的部分. 這部分初始化了BeanDefinition掃描器. 這裡的這個scanner不是spring預設的掃描包. Spring預設的掃描包不是這個scanner物件, 而是自己new的一個ClassPathBeanDefinitionScanner, Spring在執行後置處理器ConfigurationClassPostProcessor時, 去掃描包時會new一個ClassPathBeanDefinitionScanner, 這裡的scanner僅僅是為了程式設計師可以手動呼叫AnnotationConfigApplicationContext物件的scan方法, 通過呼叫context.scan("package name");掃描處理配置類

 比如,我們可以這樣使用

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

2.2 spring5原始碼 -- ioc載入的整體流程

 

首先呼叫了ClassPathBeanDefinitionScanner(this) 構造方法, 然後呼叫registerDefaultFilter註冊摩爾恩的過濾器, 這裡面預設的過濾器有兩種: javax.annotation.ManagedBean 和 javax.inject.Named. 同時隱含的會註冊所有帶有@Component @Repository @Controller關鍵字的註解

    @SuppressWarnings("unchecked")
    protected void registerDefaultFilters() {
        this.includeFilters.add(new AnnotationTypeFilter(Component.class));
        ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
        try {
            this.includeFilters.add(new AnnotationTypeFilter(
                    ((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
            logger.trace("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
        }
        catch (ClassNotFoundException ex) {
            // JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
        }
        try {
            this.includeFilters.add(new AnnotationTypeFilter(
                    ((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
            logger.trace("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
        }
        catch (ClassNotFoundException ex) {
            // JSR-330 API not available - simply skip.
        }
    }

 

在ClassPathBeanDefinitionScanner中, 有一個非常重要的方法, 就是doScan(String ....beanPackages). 用來掃描傳入的配置檔案.

 

五.  註冊配置方法

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

這是AnnotationConfigApplicationContext方法的建構函式, 裡面第二步呼叫了register()方法. 

 2.2 spring5原始碼 -- ioc載入的整體流程

 

 

  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);
            }
        }

        BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
        definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
        BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
    }

AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);用來載入bean後設資料中的註解

BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);用來註冊bean定義. 經過一些列的教研, 沒有問題, 然後將其讓入到this.beanDefinitionMap.put(beanName, beanDefinition);中
具體做了哪些工作, 可以看看上面的結構圖

 六. Refresh() -- spring ioc容器重新整理方法

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

refresh()方法, spring有很多衍生品, 比如spring mvc ,spring boot, 都有這個方法. refresh()裡面定義了spring ioc中bean載入的全過程. 

    @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工廠的後置處理器
                 * 1. 會再次class掃描成BeanDefinition
                 */
                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();
            }

            catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                }

                // Destroy already created singletons to avoid dangling resources.
                destroyBeans();

                // Reset 'active' flag.
                cancelRefresh(ex);

                // Propagate exception to caller.
                throw ex;
            }

            finally {
                // Reset common introspection caches in Spring's core, since we
                // might not ever need metadata for singleton beans anymore...
                resetCommonCaches();
            }
        }
    }

這是refresh()的原始碼, 在refresh()中做了很多很多事情, 我們這次主要看和ioc中beanFactory建立bean有關的部分.

 

一個是: invokeBeanFactoryPostProcessors(beanFactory);

另一個是: finishBeanFactoryInitialization(beanFactory);

 

6.1 invokeBeanFactoryPostProcessors(beanFactory) 呼叫BeanFactory的後置處理器

 在AnnotatedBeanDefinitionReader這裡掃描了所有後置處理器, 將其解析到beanDefinitionMap, 在這裡呼叫後置處理器

 

6.2 finishBeanFactoryInitialization 例項化剩餘的單例項bean

 這個方法就是迴圈遍歷BeanDefinitionMap, 呼叫getBean, 去生產bean

 

這裡第一個是: 凍結配置類, 意思是說, 我馬上就要開始製造bean了, bean配置檔案不能再修改了, 所以被凍結

原理是有一個變數標記, 設為true標記凍結.

    @Override
    public void freezeConfiguration() {
        this.configurationFrozen = true;
        this.frozenBeanDefinitionNames = StringUtils.toStringArray(this.beanDefinitionNames);
    }

 

第二個是例項化建立bean

Override
    protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
            throws BeanCreationException {

        if (logger.isTraceEnabled()) {
            logger.trace("Creating instance of bean '" + beanName + "'");
        }
        RootBeanDefinition mbdToUse = mbd;

        // Make sure bean class is actually resolved at this point, and
        // clone the bean definition in case of a dynamically resolved Class
        // which cannot be stored in the shared merged bean definition.
        // 確保此時的bean已經被解析了
        Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
        if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
            mbdToUse = new RootBeanDefinition(mbd);
            mbdToUse.setBeanClass(resolvedClass);
        }

        // Prepare method overrides.
        try {
            /**
             * 驗證和準備覆蓋方法(近在xml方式中)
             * lookup-method 和 replace-method
             * 這兩個配置存放在BeanDefinition中的methodOverrides(僅在XML方式中)
             * 在XML方式中, bean例項化的過程中如果檢測到存在methodOverrides
             * 則會動態的為當前bean生成代理並使用對應的攔截器為bean做增強處理
             * 具體的實現我們後續分析. 現在先看mbdtoUse.prepareMethodOverrides()程式碼塊
             */
            mbdToUse.prepareMethodOverrides();
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
                    beanName, "Validation of method overrides failed", ex);
        }

        try {
            // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
            /**
             * 初始化之前的解析
             * 第一次呼叫bean後置處理器
             * 銅鼓bean的後置處理器來進行後置處理生成代理物件, 一般情況下在此處不會生成代理物件
             * 為什麼不能生成代理物件? 不管是我們的JDK還是cglib代理都不會在此處進行代理, 因為我們的真實物件沒有生成,
             * 所以在這裡不會生成代理物件
             * 這一步是aop和事務的關鍵, 因為在這解析我們的aop切面資訊進行快取.
             */
            Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
            if (bean != null) {
                return bean;
            }
        }
        catch (Throwable ex) {
            throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
                    "BeanPostProcessor before instantiation of bean failed", ex);
        }

        try {
            /*
             * 執行建立bean, 這裡就是執行建立bean的三個步驟
             * 1. 例項化
             * 2. 填充屬性, @Autowired @Value
             * 3. 初始化  初始化initMethod方法和初始化destroy方法
             */
            Object beanInstance = doCreateBean(beanName, mbdToUse, args);
            if (logger.isTraceEnabled()) {
                logger.trace("Finished creating instance of bean '" + beanName + "'");
            }
            return beanInstance;
        }
        catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
            // A previously detected exception with proper bean creation context already,
            // or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
            throw ex;
        }
        catch (Throwable ex) {
            throw new BeanCreationException(
                    mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
        }
    }

 

建立bean的三個步驟 

 

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
            throws BeanCreationException {

        // Instantiate the bean.
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        if (instanceWrapper == null) {
            /**
             * 第一步: 例項化
             * 這裡面的呼叫鏈非常深, 後面再看
             * bean例項化有兩種方式
             * 1. 使用反射:  使用反射也有兩種方式,
             *         a. 通過無參建構函式 (預設的方式)
             *             從beanDefinition中可以得到beanClass,
             *             ClassName = BeanDefinition.beanclass
             *             Class clazz = Class.forName(ClassName);
             *             clazz.newInstance();
             *             這樣就可以例項化bean了
             *
             *         b. 通過有參函式.
             *            ClassName = BeanDefinition.beanclass
             *             Class clazz = Class.forName(ClassName);
             *             Constractor con = class.getConstractor(args....)
             *             con.newInstance();
             *
             * 2. 使用工廠
             *         我們使用@Bean的方式, 就是使用的工廠模式, 自己控制例項化過程
             *
             */
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        // 這裡使用了裝飾器的設計模式
        final Object bean = instanceWrapper.getWrappedInstance();
        Class<?> beanType = instanceWrapper.getWrappedClass();
        if (beanType != NullBean.class) {
            mbd.resolvedTargetType = beanType;
        }

        // Allow post-processors to modify the merged bean definition.
        // 允許後置處理器修改已經合併的beanDefinition
        synchronized (mbd.postProcessingLock) {
            if (!mbd.postProcessed) {
                try {
                    applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                }
                catch (Throwable ex) {
                    throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                            "Post-processing of merged bean definition failed", ex);
                }
                mbd.postProcessed = true;
            }
        }

        // Eagerly cache singletons to be able to resolve circular references
        // even when triggered by lifecycle interfaces like BeanFactoryAware.
        boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                isSingletonCurrentlyInCreation(beanName));
        if (earlySingletonExposure) {
            if (logger.isTraceEnabled()) {
                logger.trace("Eagerly caching bean '" + beanName +
                        "' to allow for resolving potential circular references");
            }
            addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
        }

        // Initialize the bean instance.
        Object exposedObject = bean;
        try {
            // 第二步:填充屬性, 給屬性賦值(呼叫set方法)  這裡也是呼叫的後置處理器
            populateBean(beanName, mbd, instanceWrapper);
            // 第三步: 初始化.
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }
        catch (Throwable ex) {
            if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
                throw (BeanCreationException) ex;
            }
            else {
                throw new BeanCreationException(
                        mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
            }
        }

        if (earlySingletonExposure) {
            Object earlySingletonReference = getSingleton(beanName, false);
            if (earlySingletonReference != null) {
                if (exposedObject == bean) {
                    exposedObject = earlySingletonReference;
                }
                else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                    String[] dependentBeans = getDependentBeans(beanName);
                    Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
                    for (String dependentBean : dependentBeans) {
                        if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                            actualDependentBeans.add(dependentBean);
                        }
                    }
                    if (!actualDependentBeans.isEmpty()) {
                        throw new BeanCurrentlyInCreationException(beanName,
                                "Bean with name '" + beanName + "' has been injected into other beans [" +
                                StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
                                "] in its raw version as part of a circular reference, but has eventually been " +
                                "wrapped. This means that said other beans do not use the final version of the " +
                                "bean. This is often the result of over-eager type matching - consider using " +
                                "'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
                    }
                }
            }
        }

        // Register bean as disposable.
        try {
            registerDisposableBeanIfNecessary(beanName, bean, mbd);
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanCreationException(
                    mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
        }

        return exposedObject;
    }

 

具體結構如下:

2.2 spring5原始碼 -- ioc載入的整體流程

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

as

相關文章