Spring(八)核心容器 - Bean 創(chuàng)建過程

Spring 版本 5.0.7.RELEASE

獲取 Bean 的方法是 getBean蹬挺,其來自 BeanFactory 繼承的 AbstractAutowireCapableBeanFactory 抽象類繼承的 AbstractBeanFactory 抽象類中。

1、整體流程

public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
    
    ...
    // 通過 beanName 獲取 Bean 實例
    @Override
    public Object getBean(String name) throws BeansException {
        return doGetBean(name, null, null, false);
    }

    // 檢索所需的 bean 類型
    @Override
    public <T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException {
        return doGetBean(name, requiredType, null, false);
    }

    // 使用顯式參數(shù)創(chuàng)建 Bean 實例時要使用的參數(shù)
    @Override
    public Object getBean(String name, Object... args) throws BeansException {
        return doGetBean(name, null, args, false);
    }
    
    ...
}

getBean 有多個重載方法缸剪,可分為通過 Bean 名稱或通過 Class 獲取 Bean 對象,這些重載方法底層都是調用 doGetBean 方法该酗。

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
            @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

    /**
     * 1、如果獲取的 Bean 類型是 FactoryBean幅疼,則參數(shù) name 會以“&”為前綴。這里會去掉該修飾符昼接,并返回.
     * 2爽篷、如果是手動注冊的別名,則將其解析為規(guī)范的名稱
     */
    final String beanName = transformedBeanName(name);
    Object bean;

    /** 
     * 1慢睡、單例 Bean 在 Spring 的同一個容器內只會被創(chuàng)建一次逐工,后續(xù)再獲取 Bean,直接從單例緩存中獲取
     * 2漂辐、這里先從單例 Bean 的緩存容器中泪喊,嘗試獲取目標 Bean 
     * ( getSingleton 方法中存在解決單例 Bean 循環(huán)依賴問題的具體方案,這部分會在后面的章節(jié)詳細討論)
     */ 
    Object sharedInstance = getSingleton(beanName);
    
    // 如果存在目標 Bean
    if (sharedInstance != null && args == null) {
        if (logger.isDebugEnabled()) {
        
            // 目標 Bean 是否正在被創(chuàng)建
            if (isSingletonCurrentlyInCreation(beanName)) {
                logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
                        "' that is not fully initialized yet - a consequence of a circular reference");
            }
            else {
                logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
            }
        }

        // 1者吁、不論是單例還是原型的實例對象窘俺,最終都要通過 getObjectForBeanInstance 進行轉換饲帅,最終得到的才是符合要求的bean實例复凳。
        // 2、有時候存在如 FactoryBean 這種并不是直接返回實例本身灶泵,而是返回指定方法返回的實例
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }

    // 如果不存在目標 Bean
    else {
    
        // 如果當前正在創(chuàng)建原型 Bean育八,則處于循環(huán)依賴中,且原型 Bean 無法解決循環(huán)依賴赦邻,所以拋出異常
        if (isPrototypeCurrentlyInCreation(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName);
        }

        // 如果 beanDefinitionMap 也就是容器中不存在目標 Bean髓棋,則嘗試從父級 beanFactory 中獲取
        BeanFactory parentBeanFactory = getParentBeanFactory();
        if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
            // 獲取真正 beanName。如果獲取的 Bean 類型是 FactoryBean惶洲,則去掉 beanName 的修飾符“&”
            String nameToLookup = originalBeanName(name);
            if (parentBeanFactory instanceof AbstractBeanFactory) {
                return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
                        nameToLookup, requiredType, args, typeCheckOnly);
            }
            else if (args != null) {
                // 遞歸到 BeanFactory 中尋找
                return (T) parentBeanFactory.getBean(nameToLookup, args);
            }
            else {
                // No args -> delegate to standard getBean method.
                return parentBeanFactory.getBean(nameToLookup, requiredType);
            }
        }

        if (!typeCheckOnly) {
            // 將指定的 bean 標記為已經創(chuàng)建(或將要創(chuàng)建),即將 beanName 加入 alreadyCreated 集合中
            markBeanAsCreated(beanName);
        }

        try {
            // 通過 beanName 獲取對應的 BeanDefinition按声,如果獲取 BeanDefinition 是子類 BeanDefinition,
            // 則通過與父級合并恬吕,返回目標 bean 的 RootBeanDefinition
            final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
            // 檢查bean是否是抽象的签则,如果是則拋出異常
            checkMergedBeanDefinition(mbd, beanName, args);

            // 獲取目標 bean 所依賴的其它 bean 名稱
            String[] dependsOn = mbd.getDependsOn();
            if (dependsOn != null) {
                // 若存在依賴則需要遞歸實例化依賴的 bean
                for (String dep : dependsOn) {
                    if (isDependent(beanName, dep)) {
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                    }
                    registerDependentBean(dep, beanName);
                    try {
                        getBean(dep);
                    }
                    catch (NoSuchBeanDefinitionException ex) {
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
                    }
                }
            }

            /* 開始創(chuàng)建目標 bean 實例,根據(jù) bean 的 scope  執(zhí)行不同的創(chuàng)建方式铐料。單例渐裂,原型,其他的scope */

            // 這是單例的 bean 創(chuàng)建方式
            if (mbd.isSingleton()) {
                sharedInstance = getSingleton(beanName, () -> {
                    try {
                        // 創(chuàng)建 Bean 的核心方法
                        return createBean(beanName, mbd, args);
                    }
                    catch (BeansException ex) {
                        // Explicitly remove instance from singleton cache: It might have been put there
                        // eagerly by the creation process, to allow for circular reference resolution.
                        // Also remove any beans that received a temporary reference to the bean.
                        destroySingleton(beanName);
                        throw ex;
                    }
                });
                bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
            }

            // prototype 類型的 bean 創(chuàng)建方式
            else if (mbd.isPrototype()) {
                // It's a prototype -> create a new instance.
                Object prototypeInstance = null;
                try {
                    beforePrototypeCreation(beanName);
                    prototypeInstance = createBean(beanName, mbd, args);
                }
                finally {
                    afterPrototypeCreation(beanName);
                }
                bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
            }

            // 其它類型
            else {
                String scopeName = mbd.getScope();
                final Scope scope = this.scopes.get(scopeName);
                if (scope == null) {
                    throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
                }
                try {
                    Object scopedInstance = scope.get(beanName, () -> {
                        beforePrototypeCreation(beanName);
                        try {
                            return createBean(beanName, mbd, args);
                        }
                        finally {
                            afterPrototypeCreation(beanName);
                        }
                    });
                    bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                }
                catch (IllegalStateException ex) {
                    throw new BeanCreationException(beanName,
                            "Scope '" + scopeName + "' is not active for the current thread; consider " +
                            "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
                            ex);
                }
            }
        }
        catch (BeansException ex) {
            cleanupAfterBeanCreationFailure(beanName);
            throw ex;
        }
    }

    // 將 Bean 的類型轉換為 getBean 時指定的 requireType 類型
    if (requiredType != null && !requiredType.isInstance(bean)) {
        try {
            T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
            if (convertedBean == null) {
                throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
            }
            return convertedBean;
        }
        catch (TypeMismatchException ex) {
            if (logger.isDebugEnabled()) {
                logger.debug("Failed to convert bean '" + name + "' to required type '" +
                        ClassUtils.getQualifiedName(requiredType) + "'", ex);
            }
            throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
        }
    }
    return (T) bean;
}

整個方法的過程可以概括為:

  1. 解析 beanName
  2. 從單例 Bean 實例的緩存容器中钠惩,嘗試獲取目標 Bean 柒凉,若存在,則直接執(zhí)行最后一步篓跛,將 Bean 的類型轉換為 getBean 時指定的 requireType 類型膝捞,之后返回
  3. 若不存在,則進入創(chuàng)建 Bean 實例的流程
  4. 如果當前正在創(chuàng)建原型 Bean 實例愧沟,則處于循環(huán)依賴中蔬咬,且原型 Bean 無法解決循環(huán)依賴求泰,所以拋出異常
  5. 如果當前 BeanFactory 中不存在目標 BeanDefinition,則從父 BeanFactory 獲取
  6. 獲取目標 BeanDefinition计盒,如果獲取的 BeanDefinition 是子類 BeanDefinition(如 GenericBeanDefinition)渴频,則通過與父級合并,返回目標 bean 的 RootBeanDefinition
  7. 如果存在依賴的 Bean北启,則先實例化這些依賴的 Bean
  8. 依據(jù)當前 Bean 的作用域卜朗,開始實例化 Bean ,單例或原型
  9. 判斷實例化的 Bean 是否是 FactoryBean 類型
  10. 將 Bean 的類型轉換為 getBean 時指定的 requireType 類型
  11. 最后返回 Bean 實例

以上就是 getBean 方法的大致流程咕村,其中有兩個頻繁出現(xiàn)且非常重要的方法场钉,一個是處理 FactoryBean 的 getObjectForBeanInstance方法,另一個是創(chuàng)建 Bean 的核心實現(xiàn) createBean 方法懈涛。

2逛万、核心流程

2.1 解析 FactoryBean

關于 FactoryBean 在上一篇《Spring(七)核心容器 - 鉤子接口》文章中已經討論過,F(xiàn)actoryBean 是 Spring 提供的鉤子接口批钠,其屬于一種特殊的 Bean宇植,不同于普通的 Bean,它是用來創(chuàng)建 Bean 實例的埋心,屬于工廠 Bean指郁,不過它和普通的創(chuàng)建不同,它提供了更為靈活的方式拷呆,一般用來創(chuàng)建那些創(chuàng)建過程比較復雜的 Bean闲坎。

而 FactoryBean 則是通過 getObjectForBeanlnstance 進行解析。getObjectForBeanlnstance 是個高頻率使用的方法茬斧,無論是從緩存中獲得 bean 還是根據(jù)不同的 scope 策略加載bean腰懂。總之项秉,我們得到 bean 的實例后要做的第一步就是調用這個方法來檢測一下正確性绣溜,其實就是用于檢測當前 bean 是否是 FactoryBean 類型的 bean ,如果是伙狐,那么需要調用該 bean 對應的 FactoryBean 實例中的 getObject() 方法返回值作為真正返回的對象涮毫。

所以,當我們 getBean 的時候贷屎,有兩種可能罢防,一種是返回普通的 Bean,另一種是返回通過 getObjectForBeanInstance 方法解析 FactoryBean 返回的 Bean唉侄。

protected Object getObjectForBeanInstance(
            Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {

    // 如果 beanName 以“&”為前綴咒吐,但對應的 bean 不是 FactoryBean 類型,則拋異常
    if (BeanFactoryUtils.isFactoryDereference(name)) {
        if (beanInstance instanceof NullBean) {
            return beanInstance;
        }
        if (!(beanInstance instanceof FactoryBean)) {
            throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
        }
    }

    // 校驗已獲取的 bean 
    // 1、如果該 bean 不是 FactoryBean 類型恬叹,直接返回
    // 2候生、如果是 FactoryBean 類型,且 beanName 以“&”為前綴绽昼,說明想獲取的是 FactoryBean 唯鸭,也是直接返回
    if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
        return beanInstance;
    }

    // 從緩存中嘗試獲取 FactoryBean 創(chuàng)建的對象
    Object object = null;
    if (mbd == null) {
        object = getCachedObjectForFactoryBean(beanName);
    }
    if (object == null) {
        // 到這里已確定 beanInstance 一定是 FactoryBean 類型,所以進行強轉
        FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
        // 獲取 bean 對應的 BeanDefinition
        if (mbd == null && containsBeanDefinition(beanName)) {
            mbd = getMergedLocalBeanDefinition(beanName);
        }
        // 當前 bean 是否是用戶定義的硅确,而不是應用程序自己定義的
        boolean synthetic = (mbd != null && mbd.isSynthetic());
        
        // 解析 FactoryBean 的核心方法
        object = getObjectFromFactoryBean(factory, beanName, !synthetic);
    }
    return object;
}

這個方法很簡單目溉,大多是些輔助代碼以及一些功能性的判斷,真正的核心代碼在 getObjectFromFactoryBean 方法中菱农。

protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
    // 如果是單例 bean 
    if (factory.isSingleton() && containsSingleton(beanName)) {
        synchronized (getSingletonMutex()) {
            // 嘗試從緩存中獲取缭付,緩存中存儲的是已經通過 FactoryBean 創(chuàng)建的 bean 
            Object object = this.factoryBeanObjectCache.get(beanName);
            if (object == null) {
            
                // 通過 FactoryBean 創(chuàng)建真正的 bean 
                object = doGetObjectFromFactoryBean(factory, beanName);
                
                // 這里大概是 在執(zhí)行上一步 doGetObjectFromFactoryBean 方法過程中,該 bean 已被其它線程創(chuàng)建并緩存了起來
                Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
                if (alreadyThere != null) {
                    object = alreadyThere;
                }
                else { // 如果沒有
                    if (shouldPostProcess) { // Bean 是否要進行后置處理
                        ...
                        
                        try {
                            // 執(zhí)行后置處理器(關于后置處理器已在上篇文章討論過)
                            object = postProcessObjectFromFactoryBean(object, beanName);
                        }
                        
                        // catch ...
                    }
                    ...
                }
            }
            return object;
        }
    }
    else { // 如果不是單例 bean 
        // 通過 FactoryBean 創(chuàng)建真正的 bean 
        Object object = doGetObjectFromFactoryBean(factory, beanName);
        if (shouldPostProcess) {
            try {
                // 執(zhí)行后置處理器
                object = postProcessObjectFromFactoryBean(object, beanName);
            }
            // catch ...
        }
        return object;
    }
}

接著進入該方法中更為核心的 doGetObjectFromFactoryBean 方法:

private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
            throws BeanCreationException {

    Object object;
    try {
        // try...catch...
        
        else {
            // 調用 FactoryBean 的 getObject 方法循未,返回真正的 bean
            object = factory.getObject();
        }
    }
    
    // try...catch...

    ...
    
    return object;
}

可以看到陷猫,最后調用的就是 FactoryBean.getObject 方法

public interface FactoryBean<T> {
    @Nullable
    T getObject() throws Exception;
}

當某個 bean 的實例化過程比較復雜時,可通過實現(xiàn) FactoryBean 接口的妖,然后在重寫的 getObject 方法中定義實例化 bean 的邏輯绣檬,以后獲取該 bean 時,會通過調用 getObject 方法進行返回羔味。值得注意的是 mybatis 底層就是通過 FactoryBean 來實現(xiàn)河咽。

2.2 從 createBean 開始

接著進入創(chuàng)建 Bean 的下一步 createBean 方法:

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

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

    // 根據(jù)設置的 class 屬性或 className 來解析得到 Class 引用
    if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
        mbdToUse = new RootBeanDefinition(mbd);
        mbdToUse.setBeanClass(resolvedClass);
    }

    // 對 override 屬性進行標記和驗證,本質上是處理 lookup-method 和 replaced-method 標簽
    try {
        mbdToUse.prepareMethodOverrides();
    }
    // catch...

    try {
        // 執(zhí)行 BeanPostProcessors 后置處理器赋元,如果有 bean 返回,則不執(zhí)行接下來創(chuàng)建 bean 的操作飒房,直接返回該 bean 
        Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
        if (bean != null) {
            return bean;
        }
    }
    // catch...

    try {
        // 創(chuàng)建 Bean 的核心方法
        Object beanInstance = doCreateBean(beanName, mbdToUse, args);
        if (logger.isDebugEnabled()) {
            logger.debug("Finished creating instance of bean '" + beanName + "'");
        }
        return beanInstance;
    }
    // catch...
}

繼續(xù)進入 doCreateBean 方法中:

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

    // BeanWrapper 包裝了 bean 對象搁凸,緩存了 bean 的內省結果,并可以訪問 bean 的屬性狠毯、設置 bean 的屬性值
    BeanWrapper instanceWrapper = null;
    // 如果是單例护糖,嘗試獲取對應的 BeanWrapper
    if (mbd.isSingleton()) {
        instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    }
    if (instanceWrapper == null) {
        /*
         * 說明對應的bean還沒有創(chuàng)建,用對應的策略(工廠方法嚼松、構造函數(shù))創(chuàng)建 bean 實例嫡良,以及簡單初始化
         *
         * 將 beanDefinition 轉成 BeanWrapper,大致流程如下:
         * 1. 如果存在工廠方法献酗,則使用工廠方法初始化
         * 2. 否則寝受,如果存在多個構造函數(shù),則根據(jù)參數(shù)確定構造函數(shù)罕偎,并利用構造函數(shù)初始化
         * 3. 否則很澄,使用默認構造函數(shù)初始化
         */
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    // 從 BeanWrapper 中獲取包裝的 bean 實例
    final Object bean = instanceWrapper.getWrappedInstance();
    // 從 BeanWrapper 獲取包裝 bean 的 class 引用
    Class<?> beanType = instanceWrapper.getWrappedClass();
    if (beanType != NullBean.class) {
        mbd.resolvedTargetType = beanType;
    }

    // 執(zhí)行 MergedBeanDefinitionPostProcessor 后置處理器。
    //(這里涉及一個極其重要的后置處理器實現(xiàn) AutowiredAnnotationBeanPostProcessor,其主要用來處理 @Autowired 注解甩苛,這部分會在后面詳細討論)
    synchronized (mbd.postProcessingLock) {
        if (!mbd.postProcessed) {
            try {
                applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
            }
            // catch...
            mbd.postProcessed = true;
        }
    }

    //  檢查是否需要提前曝光蹂楣,避免循環(huán)依賴(循環(huán)依賴問題會在后面詳細討論)
    boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
            isSingletonCurrentlyInCreation(beanName));
    if (earlySingletonExposure) {
        if (logger.isDebugEnabled()) {
            logger.debug("Eagerly caching bean '" + beanName +
                    "' to allow for resolving potential circular references");
        }
        addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    }

    // 開始初始化 bean 
    Object exposedObject = bean;
    try {
        // 對 bean 進行填充,將各個屬性值注入讯蒲,如果存在依賴的 bean 則進行遞歸初始化
        populateBean(beanName, mbd, instanceWrapper);
        // 執(zhí)行一系列的初始化方法
        exposedObject = initializeBean(beanName, exposedObject, mbd);
    }
    // catch...

    // 再次檢查是否循環(huán)依賴
    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 
                }
            }
        }
    }

    // 注冊DisposableBean
    try {
        registerDisposableBeanIfNecessary(beanName, bean, mbd);
    }
    // catch...

    return exposedObject;
}

該方法整體流程如下:

  1. 如果是單例痊土,嘗試從緩存中獲取 bean 的包裝器 BeanWrapper,并清除緩存
  2. 如果不存在對應的 Wrapper墨林,則說明 bean 未被實例化施戴,創(chuàng)建 bean 實例
  3. 執(zhí)行 MergedBeanDefinitionPostProcessor 后置處理器
  4. 檢查是否需要提前曝光,避免循環(huán)依賴
  5. 屬性填充萌丈,將所有屬性填充至bean 的實例中赞哗。
  6. 執(zhí)行一系列的初始化方法(回調鉤子接口)
  7. 再次檢查是否存在循環(huán)依賴
  8. 注冊 DisposableBean

該過程中有幾個需要重點介紹的方法,分別是創(chuàng)建 Bean 實例的 createBeaninstance 方法辆雾、注入 Bean 屬性的 populateBean 方法以及執(zhí)行 Bean 初始化方法的 initializeBean 方法肪笋。

2.2.1 創(chuàng)建 Bean 實例

從 createBeaninstance 開始:

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
    Class<?> beanClass = resolveBeanClass(mbd, beanName);
    if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
    }

    // 如果有用于創(chuàng)建 bean 實例的回調方法
    Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
    if (instanceSupplier != null) {
        return obtainFromSupplier(instanceSupplier, beanName);
    }
    
    // 如果工廠方法不為空,則使用工廠方法進行實例化
    if (mbd.getFactoryMethodName() != null)  {
        return instantiateUsingFactoryMethod(beanName, mbd, args);
    }

    // 利用構造函數(shù)進行實例化度迂,解析并確定目標構造函數(shù)
    boolean resolved = false;
    boolean autowireNecessary = false;
    if (args == null) {
        synchronized (mbd.constructorArgumentLock) {
            // 一個類可能有多個構造函數(shù)藤乙,需要根據(jù)參數(shù)來確定具體的構造函數(shù)
            if (mbd.resolvedConstructorOrFactoryMethod != null) {
                resolved = true;
                autowireNecessary = mbd.constructorArgumentsResolved;
            }
        }
    }
    
    // 如果已經解析過,則使用已經確定的構造方法
    if (resolved) {
        if (autowireNecessary) {
            // 依據(jù)構造函數(shù)注入
            return autowireConstructor(beanName, mbd, null, null);
        }
        else {
            // 使用默認構造函數(shù)構造
            return instantiateBean(beanName, mbd);
        }
    }

    // 根據(jù)參數(shù)確定構造函數(shù)
    Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
    if (ctors != null ||
            mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
            mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
        return autowireConstructor(beanName, mbd, ctors, args);
    }

    // 使用默認的構造函數(shù)
    return instantiateBean(beanName, mbd);
}

以上主要分為:

  1. 使用工廠方法進行實例化
  2. 通過構造函數(shù)實例化

不管是通過工廠方法還是構造方法來實例化對象惭墓,到這里得到的也僅僅是一個 bean 的最初實例坛梁,還不是我們最終期望的 bean,因為后面還需要對 bean 實例進行初始化處理腊凶,注入相應的屬性值等划咐。

2.2.2 初始化 Bean 實例 - 屬性注入

屬性注入通過 populateBean 方法實現(xiàn):

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
    // 判斷實例化的 bean 是否為空
    if (bw == null) {
        // 返回是否有為此 bean 定義的屬性值,如果有钧萍,則拋異常褐缠,提示 “無法將屬性值應用于空實例”
        if (mbd.hasPropertyValues()) {
            throw new BeanCreationException(
                    mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
        }
        // 沒有,則跳過屬性填充階段以獲取空實例
        else {
            // Skip property population phase for null instance.
            return;
        }
    }

    // 在設置屬性之前风瘦,先執(zhí)行 InstantiationAwareBeanPostProcessors 后置處理器队魏,這些后置處理器可以用其它方式注入屬性,如字段注入万搔。
    boolean continueWithPropertyPopulation = true;
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof InstantiationAwareBeanPostProcessor) {
                InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                    continueWithPropertyPopulation = false;
                    break;
                }
            }
        }
    }
    // 當使用了 InstantiationAwareBeanPostProcessors 后置處理器注入屬性胡桨,則結束屬性注入流程,直接返回
    if (!continueWithPropertyPopulation) {
        return;
    }

    // 獲取 bean 實例的屬性值集合
    PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

    if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
            mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
        MutablePropertyValues newPvs = new MutablePropertyValues(pvs);

        // 根據(jù)名稱自動注入
        if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
            autowireByName(beanName, mbd, bw, newPvs);
        }

        // 根據(jù)類型自動注入
        if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
            autowireByType(beanName, mbd, bw, newPvs);
        }

        pvs = newPvs;
    }

    // 返回此工廠是否擁有 InstantiationAwareBeanPostProcessor
    boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
    // 是否進行依賴檢查
    boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);

    if (hasInstAwareBpps || needsDepCheck) {
        if (pvs == null) {
            pvs = mbd.getPropertyValues();
        }
        PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
        // 在屬性注入前執(zhí)行 InstantiationAwareBeanPostProcessor 后置處理器
        if (hasInstAwareBpps) {
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof InstantiationAwareBeanPostProcessor) {
                    InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                    pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                    if (pvs == null) {
                        return;
                    }
                }
            }
        }
        // 進行依賴檢查
        if (needsDepCheck) {
            checkDependencies(beanName, mbd, filteredPds, pvs);
        }
    }

    if (pvs != null) {
        // 執(zhí)行屬性注入
        applyPropertyValues(beanName, mbd, bw, pvs);
    }
}

2.2.3 初始化 Bean 實例 - 執(zhí)行初始化方法(回調鉤子接口)

接著進入 initializeBean 方法瞬雹,在該方法中會回調許多在 Bean 初始化階段執(zhí)行的方法昧谊。

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {

    // 回調 Aware 系列接口
    if (System.getSecurityManager() != null) {
        AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
            invokeAwareMethods(beanName, bean);
            return null;
        }, getAccessControlContext());
    }
    else {
        invokeAwareMethods(beanName, bean);
    }

    // 回調 BeanPostProcessor 后置處理器的 postProcessBeforeInitialization 方法
    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }

    try {
        // 回調 InitializingBean 的 afterPropertiesSet 方法
        invokeInitMethods(beanName, wrappedBean, mbd);
    }
    catch (Throwable ex) {
        throw new BeanCreationException(
                (mbd != null ? mbd.getResourceDescription() : null),
                beanName, "Invocation of init method failed", ex);
    }
    if (mbd == null || !mbd.isSynthetic()) {
        // 回調 BeanPostProcessor 后置處理器的 postProcessAfterInitialization 方法
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }

    return wrappedBean;
}

可以看到,在 Bean 的初始化階段挖炬,分別回調了 Aware 系列接口揽浙、BeanPostProcessor 后置處理器状婶、InitializingBean 。這三個接口都屬于 Spring 的鉤子接口馅巷,是 Spring 開放出來的擴展接口膛虫,可以影響 Bean 的生命周期。關于鉤子接口在上一篇的《Spring(七)核心容器 - 鉤子接口》文章已詳細討論钓猬,感興趣的同學可自行翻閱稍刀。

1、回調 Aware 系列接口

private void invokeAwareMethods(final String beanName, final Object bean) {   
    
    if (bean instanceof Aware) {
        // 如果當前 Bean 繼承了 BeanNameAware 接口敞曹,則回調接口中的 setBeanName 方法账月,并傳遞 beanName 參數(shù)
        if (bean instanceof BeanNameAware) {
            ((BeanNameAware) bean).setBeanName(beanName);
        }
        
        // 這個 BeanClassLoaderAware 接口傳遞的是 ClassLoader
        if (bean instanceof BeanClassLoaderAware) {
            ClassLoader bcl = getBeanClassLoader();
            if (bcl != null) {
                ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
            }
        }
        
        // 這個 BeanFactoryAware 接口傳遞的是 AbstractAutowireCapableBeanFactory
        if (bean instanceof BeanFactoryAware) {
            ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
        }
    }
}

這里被回調的 Aware 接口有三個,分別是 BeanNameAware 澳迫、BeanClassLoaderAware局齿、BeanFactoryAware。

2橄登、回調 BeanPostProcessor 后置處理器的 postProcessBeforeInitialization 方法

public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
            throws BeansException {

    Object result = existingBean;
    
    // getBeanPostProcessors 方法獲取所有的 BeanPostProcessor 后置處理器的實現(xiàn)抓歼,并循環(huán)執(zhí)行 postProcessBeforeInitialization 方法,參數(shù)是當前 Bean 以及 beanName 拢锹。
    for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
        Object current = beanProcessor.postProcessBeforeInitialization(result, beanName);
        if (current == null) {
            return result;
        }
        result = current;
    }
    return result;
}

其中有一個后置處理器的實現(xiàn) ApplicationContextAwareProcessor 谣妻,其用來對剩余的 Aware 接口進行回調:

@Override
public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
        AccessControlContext acc = null;

    //...
    
        invokeAwareInterfaces(bean);
    //...

    return bean;
}
private void invokeAwareInterfaces(Object bean) {
    if (bean instanceof Aware) {
        if (bean instanceof EnvironmentAware) {
            ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
        }
        if (bean instanceof EmbeddedValueResolverAware) {
            ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
        }
        if (bean instanceof ResourceLoaderAware) {
            ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
        }
        if (bean instanceof ApplicationEventPublisherAware) {
            ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
        }
        if (bean instanceof MessageSourceAware) {
            ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
        }
        if (bean instanceof ApplicationContextAware) {
            ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
        }
    }
}

3、回調 InitializingBean 的 afterPropertiesSet 方法

protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
            throws Throwable {

    //..
            ((InitializingBean) bean).afterPropertiesSet();
    
    //..
}

4卒稳、回調 BeanPostProcessor 后置處理器的 postProcessAfterInitialization 方法

@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
        throws BeansException {

    Object result = existingBean;
    
    // getBeanPostProcessors 方法獲取所有的 BeanPostProcessor 后置處理器的實現(xiàn)蹋半,并循環(huán)執(zhí)行 postProcessAfterInitialization 方法,參數(shù)是當前 Bean 以及 beanName 充坑。
    for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
        Object current = beanProcessor.postProcessAfterInitialization(result, beanName);
        if (current == null) {
            return result;
        }
        result = current;
    }
    return result;
}

到這里减江,創(chuàng)建 Bean 的核心流程就討論結束,可歸納為:

  1. 解析 beanName
  2. 從單例 Bean 實例的緩存容器中匪傍,嘗試獲取目標 Bean
  3. 緩存不存在則開始實例化 Bean 您市,區(qū)分單例或原型
  4. 實例化 Bean、初始化 Bean役衡、執(zhí)行初始化方法及回調鉤子接口
  5. 判斷實例化的 Bean 是否是 FactoryBean 類型







參考《Spring源碼深度解析(第2版)》

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市薪棒,隨后出現(xiàn)的幾起案子手蝎,更是在濱河造成了極大的恐慌,老刑警劉巖俐芯,帶你破解...
    沈念sama閱讀 212,029評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件棵介,死亡現(xiàn)場離奇詭異,居然都是意外死亡吧史,警方通過查閱死者的電腦和手機邮辽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,395評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人吨述,你說我怎么就攤上這事岩睁。” “怎么了揣云?”我有些...
    開封第一講書人閱讀 157,570評論 0 348
  • 文/不壞的土叔 我叫張陵捕儒,是天一觀的道長。 經常有香客問我邓夕,道長刘莹,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,535評論 1 284
  • 正文 為了忘掉前任焚刚,我火速辦了婚禮点弯,結果婚禮上,老公的妹妹穿的比我還像新娘矿咕。我一直安慰自己抢肛,他們只是感情好,可當我...
    茶點故事閱讀 65,650評論 6 386
  • 文/花漫 我一把揭開白布痴腌。 她就那樣靜靜地躺著雌团,像睡著了一般。 火紅的嫁衣襯著肌膚如雪士聪。 梳的紋絲不亂的頭發(fā)上锦援,一...
    開封第一講書人閱讀 49,850評論 1 290
  • 那天,我揣著相機與錄音剥悟,去河邊找鬼灵寺。 笑死,一個胖子當著我的面吹牛区岗,可吹牛的內容都是我干的略板。 我是一名探鬼主播,決...
    沈念sama閱讀 39,006評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼慈缔,長吁一口氣:“原來是場噩夢啊……” “哼叮称!你這毒婦竟也來了?” 一聲冷哼從身側響起藐鹤,我...
    開封第一講書人閱讀 37,747評論 0 268
  • 序言:老撾萬榮一對情侶失蹤瓤檐,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后娱节,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體挠蛉,經...
    沈念sama閱讀 44,207評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,536評論 2 327
  • 正文 我和宋清朗相戀三年肄满,在試婚紗的時候發(fā)現(xiàn)自己被綠了谴古。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片质涛。...
    茶點故事閱讀 38,683評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖掰担,靈堂內的尸體忽然破棺而出汇陆,到底是詐尸還是另有隱情,我是刑警寧澤恩敌,帶...
    沈念sama閱讀 34,342評論 4 330
  • 正文 年R本政府宣布瞬测,位于F島的核電站,受9級特大地震影響纠炮,放射性物質發(fā)生泄漏月趟。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,964評論 3 315
  • 文/蒙蒙 一恢口、第九天 我趴在偏房一處隱蔽的房頂上張望孝宗。 院中可真熱鬧,春花似錦耕肩、人聲如沸因妇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,772評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽婚被。三九已至,卻和暖如春梳虽,著一層夾襖步出監(jiān)牢的瞬間址芯,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,004評論 1 266
  • 我被黑心中介騙來泰國打工窜觉, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留谷炸,地道東北人。 一個月前我還...
    沈念sama閱讀 46,401評論 2 360
  • 正文 我出身青樓禀挫,卻偏偏與公主長得像旬陡,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子语婴,可洞房花燭夜當晚...
    茶點故事閱讀 43,566評論 2 349

推薦閱讀更多精彩內容