Spring學習之——Bean加載流程

Spring IOC容器就像是一個生產產品的流水線上的機器,Spring創建出來的Bean就好像是流水線的終點生產出來的一個個精美絕倫的產品。既然是機器,總要先啓動,Spring也不例外。因此Bean的加載流程總體上來說可以分爲兩個階段:

  • 容器啓動階段
  • Bean創建階段

一、容器啓動階段:

容器的啓動階段做了很多的預熱工作,爲後面Bean的實例化做好了充分的準備,我們首先看一下容器的啓動階段都做了哪些預熱工作。

1、配置元信息:

Spring IOC容器將對象實例的創建與對象實例的使用分離,當業務中需要依賴某個對象,不再依靠我們自己手動創建,只需向Spring要,Spring就會以注入的方式交給我們需要的依賴對象。既然將對象創建的任務交給了Spring,那麼Spring就需要知道創建一個對象所需要的一些必要的信息。而這些必要的信息可以是Spring過去支持最完善的xml配置文件,或者是其他形式的例如properties的磁盤文件,也可以是現在主流的註解,甚至是直接的代碼硬編碼。總之,這些創建對象所需要的必要信息稱爲配置元信息。

<bean id="role" class="com.wbg.springxmlbean.entity.Role">
    <!-- property元素是定義類的屬性,name屬性定義的是屬性名稱 value是值
    相當於:
    Role role=new Role();
    role.setId(1);
    role.setRoleName("高級工程師");
    role.setNote("重要人員");-->
    <property name="id" value="1"/>
    <property name="roleName" value="高級工程師"/>
    <property name="note" value="重要人員"/>
</bean>

2、BeanDefination:

在Java世界中,萬物皆對象,散落於程序代碼各處的註解以及保存在磁盤上的xml或者其他文件等等配置元信息,在內存中總要以一種對象的形式表示,就好比我們活生生的人對應到Java世界中就是一個Person類,而Spring選擇在內存中表示這些配置元信息的方式就是BeanDefination,這裏我們不會去分析BeanDefination的代碼,這裏我們只需要知道配置元信息被加載到內存之後是以BeanDefination的形存在的即可。

3、BeanDefinationReader:

Spring是如何看懂這些配置元信息的呢?這個就要靠我們的BeanDefinationReader了。不同的BeanDefinationReader擁有不同的功能,如果我們要讀取xml配置元信息,那麼可以使用XmlBeanDefinationReader。如果我們要讀取properties配置文件,那麼可以使用PropertiesBeanDefinitionReader加載。而如果我們要讀取註解配置元信息,那麼可以使用 AnnotatedBeanDefinitionReader加載。我們也可以很方便的自定義BeanDefinationReader來自己控制配置元信息的加載。總的來說,BeanDefinationReader的作用就是加載配置元信息,並將其轉化爲內存形式的BeanDefination,存在某一個地方,至於這個地方在哪裏,不要着急,接着往下看!

4、BeanDefinationRegistry:

執行到這裏,Spring已經將存在於各處的配置元信息加載到內存,並轉化爲BeanDefination的形式,這樣我們需要創建某一個對象實例的時候,找到相應的BeanDefination然後創建對象即可。那麼我們需要某一個對象的時候,去哪裏找到對應的BeanDefination呢?這種通過Bean定義的id找到對象的BeanDefination的對應關係或者說映射關係又是如何保存的呢?這就引出了BeanDefinationRegistry了。

Spring通過BeanDefinationReader將配置元信息加載到內存生成相應的BeanDefination之後,就將其註冊到BeanDefinationRegistry中,BeanDefinationRegistry就是一個存放BeanDefination的大籃子,它也是一種鍵值對的形式,通過特定的Bean定義的id,映射到相應的BeanDefination。

5、BeanFactoryPostProcessor:

BeanFactoryPostProcessor是容器啓動階段Spring提供的一個擴展點,主要負責對註冊到BeanDefinationRegistry中的一個個的BeanDefination進行一定程度上的修改與替換。例如我們的配置元信息中有些可能會修改的配置信息散落到各處,不夠靈活,修改相應配置的時候比較麻煩,這時我們可以使用佔位符的方式來配置。例如配置Jdbc的DataSource連接的時候可以這樣配置:

<bean id="dataSource"  
    class="org.apache.commons.dbcp.BasicDataSource"  
    destroy-method="close">  
    <property name="maxIdle" value="${jdbc.maxIdle}"></property>  
    <property name="maxActive" value="${jdbc.maxActive}"></property>  
    <property name="maxWait" value="${jdbc.maxWait}"></property>  
    <property name="minIdle" value="${jdbc.minIdle}"></property>  
  
    <property name="driverClassName"  
        value="${jdbc.driverClassName}">  
    </property>  
    <property name="url" value="${jdbc.url}"></property>  
  
    <property name="username" value="${jdbc.username}"></property>  
    <property name="password" value="${jdbc.password}"></property>  
</bean> 

BeanFactoryPostProcessor就會對註冊到BeanDefinationRegistry中的BeanDefination做最後的修改,替換$佔位符爲配置文件中的真實的數據。

至此,整個容器啓動階段就算完成了,容器的啓動階段的最終產物就是註冊到BeanDefinationRegistry中的一個個BeanDefination了,這就是Spring爲Bean實例化所做的預熱的工作。讓我們再通過一張圖的形式回顧一下容器啓動階段都是搞了什麼事吧。

 

二、Bean的獲取階段:

在容器啓動階段,已經完成了bean的註冊。如果該對象是配置成懶加載的方式,那麼直到我們向Spring要依賴對象實例之前,其都是以BeanDefinationRegistry中的一個個的BeanDefination的形式存在,也就是Spring只有在我們第一次依賴對象的時候纔開啓相應對象的實例化階段。而如果我們不是選擇懶加載的方式,容器啓動階段完成之後,其中有一個步驟finishBeanFactoryInitialization(),在這一步將立即啓動Bean實例化階段,通過隱式的調用所有依賴對象的getBean方法來實例化所有配置的Bean,完成類的加載。

1、doGetBean():bean的獲取:

doGetBean()的總體功能就是在創建bean對象之前,先去緩存或者beanFactory工廠中查看是否存在bean,如果存在,則返回,不存在,則進行對應的創建流程。我們先找到doGetBean()方法的入口,閱讀一下這個方法的源碼:

首先調用 ApplicationContext.getBean("beanName")獲取Bean對象:

applicationContext.getBean("name");

然後再調用AbstractApplicationContext.getBean("beanName"):

    public Object getBean(String name) throws BeansException {
        assertBeanFactoryActive(); 
        // 調用getBean 進入AbstractBeanFactory    
        return getBeanFactory().getBean(name);
    }

再調用AbstractBeanFactory類下面的doGetBean()方法:

protected <T> T doGetBean(
            final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
            throws BeansException {
 
        /*
        1、轉換beanName(別名轉換):傳入的參數name可能只是別名,也可能是FactoryBean,所以需要進行解析轉換:
        (1)消除修飾符,比如工廠引用前綴 String FACTORY_BEAN_PREFIX = "&";
        (2)解決spring中alias標籤的別名問題
        */ 
        final String beanName = transformedBeanName(name);
        Object bean;
 
        //2、嘗試從緩存中去加載實例,如果獲取到了就直接返回
        // Eagerly check singleton cache for manually registered singletons.
        Object sharedInstance = getSingleton(beanName);
        //如果緩存中存在對應的bean
        if (sharedInstance != null && args == null) {
            if (logger.isDebugEnabled()) {
                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 + "'");
                }
            }
            
            //3、緩存渠道的bean的實例化。從緩存中獲取的bean是原始狀態的bean,需要在這裏對bean進行bean實例化。
            // 此時會進行 合併RootBeanDefinition、BeanPostProcessor進行實例前置處理、實例化、實例後置處理。
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
        }
        // 如果緩存中沒有對應bean
        else { 
            //4、循環依賴檢查。 (構造器的循環依賴)循環依賴存在,則報錯。
            // Fail if we're already creating this bean instance:
            // We're assumably within a circular reference.
            if (isPrototypeCurrentlyInCreation(beanName)) {
                throw new BeanCurrentlyInCreationException(beanName);
            }
 
            // 5、如果緩存中沒有數據,就會轉到父類工廠去加載
            //獲取父工廠
            // Check if bean definition exists in this factory.
            BeanFactory parentBeanFactory = getParentBeanFactory();
            
            //!containsBeanDefinition(beanName)就是檢測如果當前加載的xml配置文件中不包含beanName所對應的配置,就只能到parentBeanFacotory去嘗試加載bean。
            if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
                // Not found -> check parent.
                String nameToLookup = originalBeanName(name);
                if (args != null) {
                    // Delegation to parent with explicit args.
                    return (T) parentBeanFactory.getBean(nameToLookup, args);
                }
                else {
                    // No args -> delegate to standard getBean method.
                    return parentBeanFactory.getBean(nameToLookup, requiredType);
                }
            }
 
            if (!typeCheckOnly) {
                markBeanAsCreated(beanName);
            }
 
            //6、存儲XML配置文件的GernericBeanDefinition轉換成RootBeanDefinition,即爲合併父類定義。
            try {
                // XML配置文件中讀取到的bean信息是存儲在GernericBeanDefinition中的,但Bean的後續處理是針對於RootBeanDefinition的,所以需要轉換後才能進行後續操作。
                final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                checkMergedBeanDefinition(mbd, beanName, args);
 
                // Guarantee initialization of beans that the current bean depends on.
                //7、初始化依賴的bean
                String[] dependsOn = mbd.getDependsOn();
                //bean中可能依賴了其他bean屬性,在初始化bean之前會先初始化這個bean所依賴的bean屬性。
                if (dependsOn != null) {
                    for (String dependsOnBean : dependsOn) {
                        if (isDependent(beanName, dependsOnBean)) {
                            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                    "Circular depends-on relationship between '" + beanName + "' and '" + dependsOnBean + "'");
                        }
                        registerDependentBean(dependsOnBean, beanName);
                        getBean(dependsOnBean);
                    }
                }
 
                //8、創建bean
                // Create bean instance.
                if (mbd.isSingleton()) {
                    sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
                        @Override
                        public Object getObject() throws BeansException {
                            try {
                                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);
                }
 
                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, new ObjectFactory<Object>() {
                            @Override
                            public Object getObject() throws BeansException {
                                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;
            }
        }
 
        // Check if required type matches the type of the actual bean instance.
        if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
            try {
                return getTypeConverter().convertIfNecessary(bean, requiredType);
            }
            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;
    }
 

2、從緩存中獲取單例bean:getSingleton(String beanName, boolean allowEarlyReference)

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // 從緩存池中獲取bean:singletonObjects 一級緩
    Object singletonObject = this.singletonObjects.get(beanName);
    
    // 如果一級緩存中爲null,再判斷是否正在創建
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        // 加鎖,防止併發創建
        synchronized (this.singletonObjects) {
            // 從二級緩存中獲取bean,如果此 bean 正在加載則不處理
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {
                // 當某些方法需要提前初始化,調用 addSingletonFactory 方法將對應的objectFactory 初始化策略存儲在 singletonFactories
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    singletonObject = singletonFactory.getObject();
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return singletonObject;
}

在 Spring 中,bean默認都是單例的,同一個容器的單例只會被創建一次,後續再獲取 bean 時,直接從單例緩存 singletonObjects 中進行獲取。而且因爲單例緩存是公共變量,所以對它進行操作的時候,都進行了加鎖操作,避免了多線程併發修改或讀取的覆蓋操作。

還有這裏有個 earlySingletonObjects 變量,它也是單例緩存,也是用來保存 beanName 和 創建 bean 實例之間的關係。與 singletonFactories 不同的是,當一個單例 bean 被放入到這 early 單例緩存後,就要從 singletonFactories 中移除,兩者是互斥的,主要用來解決循環依賴的問題。

3、從Bean的實例中獲取對象:getObjectForBeanInstance()

在 getBean()方法中,getObjectForBeanInstance() 是個高頻方法,在單例緩存中獲得 bean 還是 根據不同的 scope 策略加載 bean,都有這個這個方法的出現。因爲從緩存中獲取的bean是原始狀態的bean,需要在這裏對bean進行bean實例化。

 

 

方法流程小結:

  • (1)驗證 bean 類型:判斷是否是工廠bean
  • (2)對非 FactoryBean 不做處理
  • (3)處理 FactoryBean:如果是FactoryBean類型,先對 bean 進行轉換,再委託給 getObjectFromFactoryBean()方法進行處理。

在這個方法中,對工廠 bean 有特殊處理,最終獲取的是 FactoryBean.getObject() 方法返回的類型。

 

4、獲取單例:getSingleton(String beanName, ObjectFactory<?> singletonFactory)

// Create bean instance. 創建 bean 實例
// singleton 單例模式(最常使用)
if (mbd.isSingleton()) {
    // 第二個參數的回調接口,接口是 org.springframework.beans.factory.ObjectFactory#getObject
    // 接口實現的方法是 createBean(beanName, mbd, args)
    sharedInstance = getSingleton(beanName, () -> {
        return createBean(beanName, mbd, args);
        // 省略了 try / catch
    });
    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

來看 getSingleton() 方法做了什麼:

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    Assert.notNull(beanName, "Bean name must not be null");
    // 註釋 4.7 全局變量,加鎖
    synchronized (this.singletonObjects) {
        //1、再次檢查是否已經被加載了,單例模式就是可以複用已經創建的 bean
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null) {
            //2、初始化前操作,校驗是否 beanName 是否有別的線程在初始化,並記錄beanName的初始化狀態
            beforeSingletonCreation(beanName);
            boolean newSingleton = false;
            boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
            if (recordSuppressedExceptions) {
                this.suppressedExceptions = new LinkedHashSet<>();
            }
            //3、調用createBean方法實例化bean
            singletonObject = singletonFactory.getObject();
            newSingleton = true;
            if (recordSuppressedExceptions) {
                this.suppressedExceptions = null;
            }
            //4、初始化後的操作,移除初始化狀態
            afterSingletonCreation(beanName);
            if (newSingleton) {
                //5、加入緩存
                addSingleton(beanName, singletonObject);
            }
        }
        return singletonObject;
    }
}

這一步的流程就是:

  • (1)再次檢查緩存是否已經加載過
  • (2)沒有加載,則記錄beanName 的加載狀態
  • (3)調用createBean()方法實例化 bean
  • (4)bean實例化完成之後,移除初始化狀態
  • (5)將實例化結果記錄到緩存並刪除加載 bean 過程中所記錄到的各種輔助狀態

對於第(2)步和第(4)步,用來記錄 bean 的加載狀態,是用來對 循環依賴 進行檢測的。關鍵的方法在於第三步,調用了 ObjectFactory 的 getObject() 方法,實際回調接口實現的是 createBean() 方法進行創建對象。

 

三、Bean的實例化階段:

 

(一)創建bean前的準備:

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
    RootBeanDefinition mbdToUse = mbd;
    // 確保此時bean類已經被解析,並且克隆 bean 定義,以防動態解析的類不能存儲在共享合併 bean 定義中。
    //1、鎖定 class,根據設置的 class 屬性或者根據 className 來解析 Class
    Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
    if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
        mbdToUse = new RootBeanDefinition(mbd);
        mbdToUse.setBeanClass(resolvedClass);
    }
    // Prepare method overrides.
    //2、驗證及準備覆蓋的方法
    mbdToUse.prepareMethodOverrides();
    //3、解析指定bean,讓 beanPostProcessor 有機會返回代理而不是目標bean實例。
    Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
    if (bean != null) {
        // 短路操作,如果代理成功創建 bean 後,直接返回
        return bean;
    }
    
    //4、創建 bean
    Object beanInstance = doCreateBean(beanName, mbdToUse, args);
    return beanInstance;
}

先來總結這個流程:

  • (1)根據設置的 class 屬性或者根據 className 來解析 Class
  • (2)驗證及準備覆蓋的方法 這個方法是用來處理以下兩個配置的:我們在解析默認標籤時,會識別 lookup-method 和 replaced-method 屬性,然後這兩個配置的加載將會統一存放在 beanDefinition 中的 methodOverrides 屬性裏。
  • (3)應用初始化前的後處理器,解析指定 bean 是否存在初始化前的短路操作
  • (4)創建 bean

1、處理 Override 屬性:

public void prepareMethodOverrides() throws BeanDefinitionValidationException {
    // Check that lookup methods exists.
    if (hasMethodOverrides()) {
        Set<MethodOverride> overrides = getMethodOverrides().getOverrides();
        synchronized (overrides) {
            for (MethodOverride mo : overrides) {
                // 處理 override 屬性
                prepareMethodOverride(mo);
            }
        }
    }
}

可以看到,獲取類的重載方法列表,然後遍歷,一個一個進行處理。具體處理的是 lookup-method 和 replaced-method 屬性,這個步驟解析的配置將會存入 beanDefinition 中的 methodOverrides 屬性裏,是爲了待會實例化做準備。 如果 bean 在實例化時,監測到 methodOverrides 屬性,會動態地位當前 bean 生成代理,使用對應的攔截器爲 bean 做增強處理。

 

2、實例化前的前置處理:

// 讓 beanPostProcessor 有機會返回代理而不是目標bean實例。
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
    // 短路操作,如果代理成功創建 bean 後,直接返回
    return bean;
}
 
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
    Object bean = null;
    if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
        // Make sure bean class is actually resolved at this point.
        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            Class<?> targetType = determineTargetType(beanName, mbd);
            if (targetType != null) {
                // 執行前置攔截器的操作
                bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                if (bean != null) {
                    // 執行後置攔截器的操作
                    bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
                }
            }
        }
        mbd.beforeInstantiationResolved = (bean != null);
    }
    return bean;
}

在 doCreateBean() 方法前,有一個短路操作,如果後處理器成功,將會返回代理的 bean。

 

在 resolveBeforeInstantiation() 方法中,在確保 bean 信息已經被解析完成,執行了兩個關鍵方法,從註釋中看到,一個是前置攔截器的操作,另一個就是後置攔截器的操作。

 

如果第一個前置攔截器實例化成功,就已經將單例 bean 放入緩存中,它不會再經歷普通 bean 的創建過程,沒有機會進行後處理器的調用,所以在這裏的第二個步驟,就是爲了這個 bean 也能應用後處理器的 postProcessAfterInitialization 方法。而如果這個bean沒有特定的前置處理,那說明這個bean是一個普通的bean,則按照下面的步驟進行創建

(二)bean的創建:doCreateBean()

 

到了這一步,就開始真正創建bean對象了,對應的源碼就在doCreateBean()方法中,在這裏,我們先看一下bean的整體創建流程是怎麼樣的,然後再對其中的各個重要的方法作分析:

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) {
    // Instantiate the bean.
    BeanWrapper instanceWrapper = null;
    //1、如果bean是單例,就先清除緩存中的bean信息
    if (mbd.isSingleton()) {
        instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    }
    if (instanceWrapper == null) {
        //2、根據指定bean使用對應的策略實例化bean,例如:工廠方法,構造函數自動注入,簡單初始化
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    final Object bean = instanceWrapper.getWrappedInstance();
    Class<?> beanType = instanceWrapper.getWrappedClass();
    if (beanType != NullBean.class) {
        mbd.resolvedTargetType = beanType;
    }
    //3、允許後處理處理器修改合併後的bean定義
    synchronized (mbd.postProcessingLock) {
        if (!mbd.postProcessed) {
            applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
            mbd.postProcessed = true;
        }
    }
    //4、是否需要提前曝光,用來解決循環依賴時使用
    boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
            isSingletonCurrentlyInCreation(beanName));
    if (earlySingletonExposure) {
        // 第二個參數是回調接口,實現的功能是將切面動態織入 bean
        addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    }
    Object exposedObject = bean;
    //5、對 bean 進行填充,將各個屬性值注入
    // 如果存在對其它 bean 的依賴,將會遞歸初始化依賴的 bean
    populateBean(beanName, mbd, instanceWrapper);
    //6、調用初始化方法,例如 init-method
    exposedObject = initializeBean(beanName, exposedObject, mbd);
    
    //7、循環依賴檢查
    if (earlySingletonExposure) {
        Object earlySingletonReference = getSingleton(beanName, false);
        // earlySingletonReference 只有在檢測到有循環依賴的情況下才 不爲空
        if (earlySingletonReference != null) {
            if (exposedObject == bean) {
                // 如果 exposedObject 沒有在初始化方法中被改變,也就是沒有被增強
                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);
                    }
                }
                // bean 創建後,它所依賴的 bean 一定是已經創建了
                // 在上面已經找到它有依賴的 bean,如果 actualDependentBeans 不爲空
                // 表示還有依賴的 bean 沒有初始化完成,也就是存在循環依賴
                if (!actualDependentBeans.isEmpty()) {
                    throw new BeanCurrentlyInCreationException(beanName);
            }
        }
    }
    // Register bean as disposable.
    // 8、根據 scope 註冊 bean
    registerDisposableBeanIfNecessary(beanName, bean, mbd);
    return exposedObject;
}

這個doCreateBean()方法的主要流程可以總結爲:

(1)如果要加載的bean是單例,就先清除緩存中的bean信息
(2)實例化 bean,將 BeanDifinition 轉化成 BeanWrapper
(3)後置處理器修改合併後的 bean 定義:bean 合併後的處理,Autowired 註解正式通過此方法實現諸如類型的預解析
(4)依賴處理,提前暴露bean的引用,主要用於解決循環依賴的問題
(5)屬性填充:將所有屬性填充到 bean 的實例中,如果存在對其他bean的依賴,將會遞歸初始化依賴的bean
(6)初始化bean:例如afeterPropertiesSet()和init-method屬性配置的方法
(7)循環依賴檢查
(8)註冊 DisposableBean:這一步是用來處理 destroy-method 屬性,在這一步註冊,以便在銷燬對象時調用。
(9)完成創建並返回。

1、createBeanInstance():實例化bean對象

 

在上面第(2)個步驟,做的是實例化bean,然後返回BeanWrapper。

 

createBeanInstance()這一步的流程主要通過兩種方式實例化bean對象,一種是工廠方法,另一種就是構造函數,將傳進來的 RootBeanDefinition 中的配置二選一生成 bean 實例,大致介紹功能:

  • 如果存在工廠方法則使用工廠方法進行初始化
  • 如果則使用有參構造行數實例化bean:一個類有多個構造函數,每個構造函數都有不同的參數,所以需要根據參數鎖定構造函數進行 bean 的實例化
  • 如果既不存在工廠方法,也不存在帶有參數的構造函數,會使用默認的構造函數進行 bean 的實例化
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
    // Make sure bean class is actually resolved at this point.
    Class<?> beanClass = resolveBeanClass(mbd, beanName);
    Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
    // Shortcut when re-creating the same bean...
    boolean resolved = false;
    boolean autowireNecessary = false;
    if (args == null) {
        synchronized (mbd.constructorArgumentLock) {
            // 如果一個類有多個構造函數,每個構造函數都有不同的參數,調用前需要進行判斷對應的構造函數或者工廠方法
            if (mbd.resolvedConstructorOrFactoryMethod != null) {
                resolved = true;
                autowireNecessary = mbd.constructorArgumentsResolved;
            }
        }
    }
    // 如果已經解析過,不需要再次解析
    if (resolved) {
        if (autowireNecessary) {
            // 實際解析的是 org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor
            // 構造函數自動注入
            return autowireConstructor(beanName, mbd, null, null);
        }
        else {
            // 使用默認的構造函數
            return instantiateBean(beanName, mbd);
        }
    }
    // Candidate constructors for autowiring? 需要根據參數解析構造函數
    Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
    if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
            mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
        return autowireConstructor(beanName, mbd, ctors, args);
    }
    // Preferred constructors for default construction?
    ctors = mbd.getPreferredConstructors();
    if (ctors != null) {
        // 構造函數注入
        return autowireConstructor(beanName, mbd, ctors, null);
    }
    // No special handling: simply use no-arg constructor. 沒有特殊的處理,使用默認構造函數構造
    return instantiateBean(beanName, mbd);
}

在這裏,我們簡單介紹下什麼是BeanWrapper:

 

  Spring中的Bean並不是以一個個的本來模樣存在的,由於Spring IOC容器中要管理多種類型的對象,因此爲了統一對不同類型對象的訪問,Spring給所有創建的Bean實例穿上了一層外套,這個外套就是BeanWrapper,BeanWrapper實際上是對反射相關API的簡單封裝,使得上層使用反射完成相關的業務邏輯大大的簡化,我們要獲取某個對象的屬性,調用某個對象的方法,現在不需要在寫繁雜的反射API了以及處理一堆麻煩的異常,直接通過BeanWrapper就可以完成相關操作,簡直不要太爽了。

2、循環依賴:

  這裏對應前面的第(4)步的流程,提前暴露bean的引用,主要是用於解決循環依賴的問題

關鍵方法是 addSingletonFactory,作用是在 bean 開始初始化前將創建實例的 ObjectFactory 加入單例工廠,ObjectFactory 是創建對象時使用的工廠。在對象實例化時,會判斷自己依賴的對象是否已經創建好了,判斷的依據是查看依賴對象的 ObjectFactory 是否在單例緩存中,如果沒有創建將會先創建依賴的對象,然後將 ObjectFactory 放入單例緩存中。

 

這時如果有循環依賴,需要提前對它進行暴露,讓依賴方找到並正常實例化。

 

有關循環依賴的內容可以閱讀這篇文章:https://blog.csdn.net/a745233700/article/details/110914620

 

3、populateBean():屬性注入

 

這裏對應前面的第(5)步,根據不同的注入類型進行屬性填充,然後調用後處理器進行處理,最終將屬性應用到 bean 中。主要流程如下:

(1)調用 InstantiationAwareBeanPostProcessor 處理器的 postProcessAfterInstantiation 方法,判斷控制程序是否繼續進行屬性填充

(2)根據注入類型(byType/byName),提取依賴的,統一存入 PropertyValues 中

(3)判斷是否需要進行 BeanPostProcessor 和 依賴檢查:

如果有後置處理器,將會應用 InstantiationAwareBeanPostProcessor 處理器的 postProcessProperties 方法,對屬性獲取完畢填充前,對屬性進行再次處理。
使用 checkDependencies 方法來進行依賴檢查
(4)將所有解析到的 PropertyValues  中的屬性填充至 BeanWrapper 中
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
    // 給 awareBeanPostProcessor 後處理器最後一次機會,在屬性設置之前修改bean的屬性
    boolean continueWithPropertyPopulation = true;
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
        ...
        if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
            continueWithPropertyPopulation = false;
            break;
        }
        ...
    }
    PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
    int resolvedAutowireMode = mbd.getResolvedAutowireMode();
    if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
        MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
        // Add property values based on autowire by name if applicable.
        if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
            // 根據名字自動注入
            autowireByName(beanName, mbd, bw, newPvs);
        }
        // Add property values based on autowire by type if applicable.
        if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
            // 根據類型自動注入
            autowireByType(beanName, mbd, bw, newPvs);
        }
        pvs = newPvs;
    }
    // 後處理器已經初始化
    boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
    // 需要依賴檢查
    boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
    PropertyDescriptor[] filteredPds = null;
    // 從 beanPostProcessors 對象中提取 BeanPostProcessor 結果集,遍歷後處理器
    for (BeanPostProcessor bp : getBeanPostProcessors()) {
        ...
    }
    // 在前面也出現過,用來進行依賴檢查
    filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
    checkDependencies(beanName, mbd, filteredPds, pvs);
    // 將屬性應用到 bean 中,使用深拷貝,將子類的屬性一併拷貝
    applyPropertyValues(beanName, mbd, bw, pvs);
}

4、initializeBean():初始化 bean

 

這裏對應前面的第(6)步,主要是用來進行我們設定的初始化方法的調用,不過在方法內部,還做了其它操作,首先我們先看下源碼:

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
    //1、處理Aware接口
    if (System.getSecurityManager() != null) {
        AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
            invokeAwareMethods(beanName, bean);
            return null;
        }, getAccessControlContext());
    }
    else {
        // 如果沒有 securityManage,方法裏面校驗了 bean 的類型,需要引用 Aware 接口
        // 對特殊的 bean 處理:Aware/ BeanClassLoader / BeanFactoryAware
        invokeAwareMethods(beanName, bean);
    }
 
    //2、執行BeanPostProcessor前置處理:
    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }
    //3、調用用戶自定義的 init-method 方法
    invokeInitMethods(beanName, wrappedBean, mbd);
 
    //4、執行BeanPostProcessor後置處理
    if (mbd == null || !mbd.isSynthetic()) {
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }
 
    return wrappedBean;
}

這一步的流程中,主要做的處理操作有:

 

(1)處理Aware接口:

 

Spring會檢測該對象是否實現了xxxAware接口,通過Aware類型的接口,可以讓我們拿到Spring容器的一些相應的資源並注入:

  • ①如果這個Bean實現了BeanNameAware接口,會調用它實現的setBeanName(String beanId)方法,傳入Bean的名字;
  • ②如果這個Bean實現了BeanClassLoaderAware接口,調用setBeanClassLoader()方法,傳入ClassLoader對象的實例。
  • ②如果這個Bean實現了BeanFactoryAware接口,會調用它實現的setBeanFactory()方法,傳遞的是Spring工廠自身。
  • ③如果這個Bean實現了ApplicationContextAware接口,會調用setApplicationContext(ApplicationContext)方法,傳入Spring上下文;

(2)執行BeanPostProcessor前置處理:

 

如果想在Bean初始化前進行一些自定義的前置處理,那麼可以讓Bean實現了BeanPostProcessor接口,那將會調用postProcessBeforeInitialization(Object obj, String s)方法。 

(3)調用自定義的 init 方法:

這一步就是找到用戶自定義的構造函數,然後調用它。

① 如果Bean實現了InitializingBean接口,執行afeterPropertiesSet()方法

②如果Bean在Spring配置文件中配置了 init-method 屬性,則會自動調用其配置的初始化方法。

(4)執行BeanPostProcessor後置處理:

 

如果這個Bean實現了BeanPostProcessor接口,將會調用postProcessAfterInitialization(Object obj, String s)方法;由於這個方法是在Bean初始化結束時調用的,所以可以被應用於內存或緩存技術;

在容器啓動階段我們講到BeanFactoryPostProcessor,這裏我們講到BeanPostProcessor,那麼BeanFactoryPostProcessor 和 BeanPostProcessor 有什麼區別呢?

  • BeanFactoryPostProcessor存在於容器啓動階段,而BeanPostProcessor存在於對象實例化階段,BeanFactoryPostProcessor關注對象被創建之前那些配置的修改,而BeanPostProcessor階段關注對象已經被創建之後的功能增強,替換等操作,這樣就很容易區分了。
  • BeanPostProcessor與BeanFactoryPostProcessor都是Spring在Bean生產過程中強有力的擴展點。Spring中著名的AOP(面向切面編程),其實就是依賴BeanPostProcessor對Bean對象功能增強的。

5、註冊 disposableBean:

 

這一步就是根據不同的 scope 進行 disposableBean 的註冊。同時也會註冊用戶自定義的銷燬邏輯,跟自定義的初始化邏輯一樣有兩種方式:(1)DisposableBean接口的destory();(2)destory-method參數配置的方法。

protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
    AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
    if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {
        // 單例模式
        if (mbd.isSingleton()) {
            // 註冊 DisposableBean
            registerDisposableBean(beanName,new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
        }
        else {
            // A bean with a custom scope...
            Scope scope = this.scopes.get(mbd.getScope());
            scope.registerDestructionCallback(beanName,new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
        }
    }
}

6、使用與銷燬:

 

經過了以上道道工序,Spring終於將Bean創建完成了,當Spring的Bean在爲我們服務完之後,馬上就要消亡了(通常是在容器關閉的時候),這時候Spring將以回調的方式調用我們自定義的銷燬邏輯,然後Bean就這樣走完了光榮的一生!

 

7、小結:

 最後,我們再通過一張圖來一起看一看Bean實例化階段的執行順序是如何的:

 

參考文章:

https://juejin.cn/post/6844903871353978894#heading-5

https://juejin.cn/post/6929672218322731022#heading-0

 

 

版權聲明:本文爲博主原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。

原文鏈接:https://blog.csdn.net/a745233700/article/details/113840727

 

 


 



 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章