關於 Spring 中 getBean 的全流程源碼解析

做者:小傅哥
博客:https://bugstack.cnhtml

沉澱、分享、成長,讓本身和他人都能有所收穫!😄

1、前言

你提出問題,就要給出解決方案!java

最近有粉絲小夥伴反饋,與本身的上級溝通老是遇到障礙,感受不被理解。大部分時候他提出來的事情均可能會被領導說:「我沒get到你的點」、「你想作的這個項目沒有業務價值」、「你提出問題,就要給出解決方案」,等等諸如此類的回答。程序員

鑑於具體狀況要具體分析,可能咱們並不必定能判斷出是誰的問題,致使在每次的交談中出現的分歧。多是leader有leader的苦衷和視角,也多是員工有員工的理解和想法,因此最終沒有達成一致。面試

但就帶團隊來說,有效溝通很重要。就像:若是你說的都對,那我爲何和你爭吵呢?與其壓制遇到的矛盾點,不如都攤開了聊,誰的視角和心胸更大,誰就多有一些同理心。spring


若是尖銳的批評徹底消失,溫和的批評將會變得刺耳。編程

若是溫和的批評也不被容許,沉默將被認爲居心叵測。緩存

若是沉默也再也不容許,讚賞不夠賣力將是一種罪行。網絡

若是隻容許一種聲音存在,那麼,惟一存在的那個聲音就是謊話。ide

2、面試題

謝飛機,小記!,總感受 Spring 也沒啥看的,怎麼面試官一問就能問出花?函數

面試官:Spring 的 getBean 中,transformedBeanName 的做用是什麼?

謝飛機:不知道呀,看單詞意思好像是改變Bean名稱。

面試官:那這麼說,你的 Bean 若是有 alias 別名,Spring 在獲取 Bean 時候要怎麼處理?

謝飛機:這!

面試官:那若是用了 depends-on 呢?

謝飛機:啊, 我沒用過 depends-on 我不知道!

面試官:那你調試代碼時候,看見過BeanName前面有 & 的狀況嗎,爲啥會出現?

謝飛機:我不配知道!再見!

3、Bean 的獲取過程

對於剛接觸看 Spring 源碼的夥伴來講,可能很疑惑於怎麼就獲取一個 Bean 就這麼多流程呢?

  • 可能有 Bean 可能有別名、可能有依賴、也多是被 BeanFactory 包裝過,因此會有 transformedBeanName 來處理這些差別化行爲。
  • 有沒有循環依賴、有沒有父工廠、是單例仍是原型、是懶加載仍是預加載、在不在緩衝區,因此就有各類組合判斷來作不一樣的流程。
  • 提前暴漏對象、三級緩存、後置標記清楚,全部的優化處理都是爲了讓整個 Bean 的獲取更加高效。

因此,它爲了適應各種的需求,變得愈來愈複雜了。而這部分知識的深刻學習絕對不僅是爲了應付八股文,更多的是考慮到在平常的 Spring 使用中遇到複雜問題時有沒有一個大體知曉的流程,能夠快速定位問題,以及此類需求的技術實現方案是否能在之後的應用開發中起到必定的指導做用,由於它是一種設計方案的具體實現。

1. getBean 核心流程圖

小傅哥,getBean 核心流程圖

  • 整張圖就是 getBean 過程當中涉及到的類和核心流程用到的方法以及操做的內容。若是你能把整張圖全理解了,那麼基本也就看懂了 getBean 的全過程。
  • 本張圖可能會由於網絡壓縮變得不清晰,能夠經過關注公衆號bugstack蟲洞棧,回覆:圖稿,獲取。

接下來,咱們就依次的把關於獲取 Bean 實例的重點代碼列舉出來作分析,讀者夥伴也能夠結合流程圖一塊兒看,這樣會更方便理解。

2. getBean 從哪開始讀源碼

@Test
public void test_getBean() {
    BeanFactory beanFactory = new ClassPathXmlApplicationContext("spring-config.xml");
    UserDao userDao = beanFactory.getBean("userDao", UserDao.class);
    logger.info("獲取 Bean:{}", userDao);
}
  • 在平常應用到 Spring 的開發中基本都是基於註解,幾乎不會本身去使用 beanFactory.getBean 的方式去獲取一個 Bean 實例。
  • 因此在你學習的時候若是找不到查看 getBean 源碼的入口,也不方便調試熟悉源碼時,能夠寫這樣一個單元測試類,點入到 getBean 就能夠閱讀源碼了。

3. getBean 源碼全局預覽

源碼位置:AbstractBeanFactory -> getBean() -> doGetBean()

@Override
public <T> T getBean(String name, Class<T> requiredType) throws BeansException { 
    // getBean 就像你的領導其實沒作啥,都在 doGetBean 裏
    return doGetBean(name, requiredType, null, false);
}
protected <T> T doGetBean(final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
        throws BeansException {     
    
    // 處理別名BeanName、處理帶&符的工廠BeanName
    final String beanName = transformedBeanName(name);
    Object bean;  

    // 先嚐試從緩存中獲取Bean實例,這個位置就是三級緩存解決循環依賴的方法
    Object sharedInstance = getSingleton(beanName);   

    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 + "'");
            }
        }        
        
        // 1. 若是 sharedInstance 是普通的 Bean 實例,則下面的方法會直接返回
        // 2. 若是 sharedInstance 是工廠Bean類型,則須要獲取 getObject 方法,能夠參考關於 FactoryBean 的實現類 
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }
    else {
        
        // 循環依賴有三種,setter注入、多實例和構造函數,Spring 只能解決 setter 注入,因此這裏是 Prototype 則會拋出異常
        if (isPrototypeCurrentlyInCreation(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName);
        }    

        // 1. 父 bean 工廠存在
        // 2. 當前 bean 不存在於當前bean工廠,則到父工廠查找 bean 實例
        BeanFactory parentBeanFactory = getParentBeanFactory();
        if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
            // 獲取 name 對應的 beanName,若是 name 是以 & 開頭,則返回 & + beanName
            String nameToLookup = originalBeanName(name);         
            
            // 根據 args 參數是否爲空,調用不一樣的父容器方法獲取 bean 實例
            if (args != null) {
                return (T) parentBeanFactory.getBean(nameToLookup, args);
            }
            else {
                return parentBeanFactory.getBean(nameToLookup, requiredType);
            }
        }       

        // 1. typeCheckOnly,用於判斷調用 getBean 方法時,是否僅是作類型檢查
        // 2. 若是不是隻作類型檢查,就會調用 markBeanAsCreated 進行記錄
        if (!typeCheckOnly) {
            markBeanAsCreated(beanName);
        }
        try {    
    
            // 從容器 getMergedLocalBeanDefinition 獲取 beanName 對應的 GenericBeanDefinition,轉換爲 RootBeanDefinition
            final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); 
            // 檢查當前建立的 bean 定義是否爲抽象 bean 定義
            checkMergedBeanDefinition(mbd, beanName, args);
            
            // 處理使用了 depends-on 註解的依賴建立 bean 實例
            String[] dependsOn = mbd.getDependsOn();
            if (dependsOn != null) {
                for (String dep : dependsOn) {   
                    // 監測是否存在 depends-on 循環依賴,若存在則會拋出異常
                    if (isDependent(beanName, dep)) {
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                    }       
                    
                    // 註冊依賴記錄
                    registerDependentBean(dep, beanName);
                    try {    
                        // 加載 depends-on 依賴(dep 是 depends-on 縮寫)
                        getBean(dep);
                    }
                    catch (NoSuchBeanDefinitionException ex) {
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
                    }
                }
            }  

            // 建立單例 bean 實例
            if (mbd.isSingleton()) {    

                // 把 beanName 和 new ObjectFactory 匿名內部類傳入回調
                sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
                    @Override
                    public Object getObject() throws BeansException {
                        try {    
                            // 建立 bean
                            return createBean(beanName, mbd, args);
                        }
                        catch (BeansException ex) {
                            // 建立失敗則銷燬
                            destroySingleton(beanName);
                            throw ex;
                        }
                    }
                });
                bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
            }      
            // 建立其餘類型的 bean 實例
            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;
        }
    }
    // 若是須要類型轉換,這裏會進行操做
    if (requiredType != null && bean != null && !requiredType.isInstance(bean)) {
        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());
        }
    }    

    // 返回 Bean
    return (T) bean;
}

綜上基本就是 getBean 過程涉及到的核心處理方法,基本包括;

  • transformedBeanName,處理別名BeanName、處理帶&符的工廠BeanName。
  • getSingleton,先嚐試從緩存中獲取Bean實例,這個位置就是三級緩存解決循環依賴的方法。
  • getObjectForBeanInstance,若是 sharedInstance 是普通的 Bean 實例,則下面的方法會直接返回。另外 sharedInstance 是工廠Bean類型,則須要獲取 getObject 方法,能夠參考關於 FactoryBean 的實現類。
  • isPrototypeCurrentlyInCreation,循環依賴有三種,setter注入、多實例和構造函數,Spring 只能解決 setter 注入,因此這裏是 Prototype 則會拋出異常。
  • getParentBeanFactory,父 bean 工廠存在,當前 bean 不存在於當前bean工廠,則到父工廠查找 bean 實例。
  • originalBeanName,獲取 name 對應的 beanName,若是 name 是以 & 開頭,則返回 & + beanName
  • args != null,根據 args 參數是否爲空,調用不一樣的父容器方法獲取 bean 實例
  • !typeCheckOnly,typeCheckOnly,用於判斷調用 getBean 方法時,是否僅是作類型檢查,若是不是隻作類型檢查,就會調用 markBeanAsCreated 進行記錄
  • mbd.getDependsOn,處理使用了 depends-on 註解的依賴建立 bean 實例
  • isDependent,監測是否存在 depends-on 循環依賴,若存在則會拋出異常
  • registerDependentBean,註冊依賴記錄
  • getBean(dep),加載 depends-on 依賴(dep 是 depends-on 縮寫)
  • mbd.isSingleton(),建立單例 bean 實例
  • mbd.isPrototype(),建立其餘類型的 bean 實例
  • return (T) bean,返回 Bean 實例

4. beanName 轉換操做

處理 & 符:transformedBeanName() -> BeanFactoryUtils.transformedBeanName(name)

public static String transformedBeanName(String name) {
    Assert.notNull(name, "'name' must not be null");
    String beanName = name;
    while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
        beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
    }
    return beanName;
}
  • 使用 FactoryBean 建立出的對象,會在 DefaultListableBeanFactory 初始化的時候,使用 getBean(FACTORY_BEAN_PREFIX + beanName) 給 beanName 加上 & (String FACTORY_BEAN_PREFIX = "&")
  • 這裏是使用 while 循環逐步的把 & 去掉,只要截取首個字符是 & 符,就繼續循環截取。&&&userService -> &&userService -> &userService -> userService

別名轉換:transformedBeanName() -> canonicalName

public String canonicalName(String name) {
    String canonicalName = name;
    // Handle aliasing...
    String resolvedName;
    do {
        resolvedName = this.aliasMap.get(canonicalName);
        if (resolvedName != null) {
            canonicalName = resolvedName;
        }
    }
    while (resolvedName != null);
    return canonicalName;
}
<bean id="userService" class="org.itstack.interview.UserService"/>
<alias name="userService" alias="userService-alias01"/>
<alias name="userService-alias01" alias="userService-alias02"/>
  • 首先 Spring 對 Bean 的存放並不會使用別名做爲Map中的key,因此遇到全部別名獲取 Bean 都須要查到對應原來名字,才能夠。若是你知道這個事,是不遇到此類問題時,就知道從哪下手查了
  • do...while 循環會依次像鏈條同樣不斷的尋找別名對應的名稱,直到當前這個名稱沒有別名了,就返回對應 BeanName

5. depends-on 依賴 Bean

AbstractBeanFactory -> isDependent(beanName, dep) -> DefaultSingletonBeanRegistry

protected boolean isDependent(String beanName, String dependentBeanName) {
    synchronized (this.dependentBeanMap) {
        return isDependent(beanName, dependentBeanName, null);
    }
<bean id="userService" class="org.itstack.interview.UserService" depends-on="userDao"/>

<bean id="userDao" class="org.itstack.interview.UserDao"/>
  • isDependent 處理的是使用了 depends-on 配置的 Bean 定義。
private boolean isDependent(String beanName, String dependentBeanName, Set<String> alread
    if (alreadySeen != null && alreadySeen.contains(beanName)) {
        return false;
    }
    String canonicalName = canonicalName(beanName);
    Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);
    if (dependentBeans == null) {
        return false;
    }
    if (dependentBeans.contains(dependentBeanName)) {
        return true;
    }
    for (String transitiveDependency : dependentBeans) {
        if (alreadySeen == null) {
            alreadySeen = new HashSet<String>();
        }
        alreadySeen.add(beanName);
        if (isDependent(transitiveDependency, dependentBeanName, alreadySeen)) {
            return true;
        }
    }
    return false;
}
  • alreadySeen != null,監測已經依賴的 Bean
  • canonicalName,處理別名配置,找到最原來是的 BeanName
  • Set<String> dependentBeans,獲取依賴的 Bean 集合
  • for 循環遞歸檢測依賴的 Bean,並添加到 alreadySeen 中

AbstractBeanFactory -> registerDependentBean(dep, beanName) -> DefaultSingletonBeanRegistry

public void registerDependentBean(String beanName, String dependentBeanName) {
    String canonicalName = canonicalName(beanName);  

    synchronized (this.dependentBeanMap) {
        Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);
        if (dependentBeans == null) {
            dependentBeans = new LinkedHashSet<String>(8);
            this.dependentBeanMap.put(canonicalName, dependentBeans);
        }
        dependentBeans.add(dependentBeanName);
    }   

    synchronized (this.dependenciesForBeanMap) {
        Set<String> dependenciesForBean = this.dependenciesForBeanMap.get(dependentBeanName
        if (dependenciesForBean == null) {
            dependenciesForBean = new LinkedHashSet<String>(8);
            this.dependenciesForBeanMap.put(dependentBeanName, dependenciesForBean);
        }
        dependenciesForBean.add(canonicalName);
    }
}
  • canonicalName(beanName),獲取原始的 beanName
  • synchronized (this.dependentBeanMap),添加 <canonicalName, dependentBeanName> 到 dependentBeanMap 中
  • synchronized (this.dependenciesForBeanMap),添加 <dependentBeanName, canonicalName> 到 dependenciesForBeanMap 中

最後:getBean(dep),就能夠獲取到 depends-on 依賴的 Bean 了

6. 處理單實例 Bean

AbstractBeanFactory -> mbd.isSingleton()

if (mbd.isSingleton()) {
    sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
        @Override
        public Object getObject() throws BeansException {
            try {
                return createBean(beanName, mbd, args);
            }
            catch (BeansException ex) {
                destroySingleton(beanName);
                throw ex;
            }
        }
    });
    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
  • 這一部分是使用 beanName 和 singletonFactory 匿名內部類傳入等待回調的方式建立單實例 Bean 實例
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    Assert.notNull(beanName, "'beanName' must not be null");
    synchronized (this.singletonObjects) {
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null) {
            if (this.singletonsCurrentlyInDestruction) {
                throw new BeanCreationNotAllowedException(beanName,
                        "Singleton bean creation not allowed while singletons of this factory are in destruction " +
                        "(Do not request a bean from a BeanFactory in a destroy method implementation!)");
            }
            if (logger.isDebugEnabled()) {
                logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
            }
            beforeSingletonCreation(beanName);
            boolean newSingleton = false;
            boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
            if (recordSuppressedExceptions) {
                this.suppressedExceptions = new LinkedHashSet<Exception>();
            }
            try {
                singletonObject = singletonFactory.getObject();
                newSingleton = true;
            }
            catch (IllegalStateException ex) {
                singletonObject = this.singletonObjects.get(beanName);
                if (singletonObject == null) {
                    throw ex;
                }
            }
            catch (BeanCreationException ex) {
                if (recordSuppressedExceptions) {
                    for (Exception suppressedException : this.suppressedExceptions) {
                        ex.addRelatedCause(suppressedException);
                    }
                }
                throw ex;
            }
            finally {
                if (recordSuppressedExceptions) {
                    this.suppressedExceptions = null;
                }
                afterSingletonCreation(beanName);
            }
            if (newSingleton) {
                addSingleton(beanName, singletonObject);
            }
        }
        return (singletonObject != NULL_OBJECT ? singletonObject : null);
    }
}
  • this.singletonObjects.get(beanName),先嚐試從緩存池中獲取對象,沒有就繼續往下執行
  • beforeSingletonCreation(beanName),標記當前 bean 被建立,若是有構造函數注入的循環依賴會報錯
  • singletonObject = singletonFactory.getObject(),建立 bean 過程就是調用 createBean() 方法
  • afterSingletonCreation(beanName),最後把標記從集合中移除
  • addSingleton(beanName, singletonObject),新建立的會加入緩存集合

7. 從緩存中獲取 bean 實例

doCreateBean -> if (earlySingletonExposure) -> getSingleton(beanName, false)

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // 從 singletonObjects 獲取實例,singletonObjects 中緩存的實例都是徹底實例化好的 bean,能夠直接使用
    Object singletonObject = this.singletonObjects.get(beanName);
    // 若是 singletonObject 爲空,則沒有建立或建立中
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        // 加鎖
        synchronized (this.singletonObjects) {
            // 單例緩存池中,沒有當前beanName
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    // 加入到三級緩存,暴漏早期對象用於解決三級緩存
                    singletonObject = singletonFactory.getObject();  
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
  • 其實這一段代碼主要就是使用三級緩存解決set注入循環依賴的,後面會單獨列一個章節對循環依賴作相關實驗驗證
  • singletonObjects,用於存放初始化好的 bean 實例。
  • earlySingletonObjects,用於存放初始化中的 bean,來解決循環依賴。
  • singletonFactories,用於存放 bean 工廠,bean 工廠所生成的 bean 尚未完成初始化 bean。

    8. FactoryBean 中獲取 bean 實例

AbstractBeanFactory -> getObjectForBeanInstance(sharedInstance, name, beanName, null)

protected Object getObjectForBeanInstance(Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
    
    // 若是 beanName 以 & 開頭,但 beanInstance 卻不是 FactoryBean,則會拋出異常
    if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
        throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
    }

    // 這裏判斷就是這個 bean 是否是 FactoryBean,不是就直接返回了
    if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
        return beanInstance;
    }   

    Object object = null;
    if (mbd == null) {    
        // 若是 mbd 爲空,則從緩存加載 bean(FactoryBean 生成的單例 bean 實例會緩存到 factoryBeanObjectCache 集合中,方便使用)
        object = getCachedObjectForFactoryBean(beanName);
    }   

    if (object == null) {
        // 到這,beanInstance 是 FactoryBean 類型,因此就強轉了
        FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
        // mbd 爲空且判斷 containsBeanDefinition 是否包含 beanName
        if (mbd == null && containsBeanDefinition(beanName)) {    
            // 合併 BeanDefinition
            mbd = getMergedLocalBeanDefinition(beanName);
        }    
        boolean synthetic = (mbd != null && mbd.isSynthetic());   
        // 調用 getObjectFromFactoryBean 獲取實例 
        object = getObjectFromFactoryBean(factory, beanName, !synthetic);
    }
    return object;
}
  • (!(beanInstance instanceof FactoryBean),這裏判斷就是這個 bean 是否是 FactoryBean,不是就直接返回了
  • 若是 mbd 爲空,則從緩存加載 bean(FactoryBean 生成的單例 bean 實例會緩存到 factoryBeanObjectCache 集合中,方便使用)
  • 調用 getObjectFromFactoryBean 獲取實例,這裏會包括一部分對單例以及非單例的處理,以及最終返回 factory.getObject(); 對應的 Bean 實例

4、測試案例

1. 別名

<bean id="userService" class="org.itstack.interview.UserService"/>
<!-- 起個別名 -->
<alias name="userService" alias="userService-alias01"/>
<!-- 別名的別名 -->
<alias name="userService-alias01" alias="userService-alias02"/>
@Test
public void test_alias() {
    BeanFactory beanFactory = new ClassPathXmlApplicationContext("spring-config-alias.xml");
    UserService userService = beanFactory.getBean("userService-alias02", UserService.class);
    logger.info("獲取 Bean 經過別名:{}", userService);
}

  • 在單元測試 getBean 的時候,會看到它會把別名逐步處理掉,最終獲取到原有的 BeanName

2. 依賴

<bean id="userService" class="org.itstack.interview.UserService" depends-on="userDao"/>
<bean id="userDao" class="org.itstack.interview.UserDao"/>
@Test
public void test_depends_on() {
    BeanFactory beanFactory = new ClassPathXmlApplicationContext("spring-config-depends-on.xml");
    UserService userService = beanFactory.getBean(UserService.class, "userService");
    logger.info("獲取 Bean:{}", userService.getUserDao());
}

  • 涉及到依賴會走到 dependsOn != null 下,獲取到依賴的 Bean 實例。

3. BeanFactory

<bean id="userDao" class="org.itstack.interview.MyFactoryBean"/>
@Test
public void test_factory_bean() {
    BeanFactory beanFactory = new ClassPathXmlApplicationContext("spring-config-factory-bean.xml");
    UserDao userDao = beanFactory.getBean("userDao", UserDao.class);
    logger.info("獲取 Bean:{}", userDao);
}

  • 實現 FactoryBean 的類會須要實現 getObject 方法,全部此類的 Bean 最終都是獲取 getObject

5、總結

  • 到這裏關於 Spring IOC 獲取 Bean 的核心流程基本就所有介紹完了,整個篇章讓咱們看到獲取一個 Bean 的流程也是很是複雜的,涉及到了很是多的分支流程。之全部會有這麼多的流程,就是咱們前面介紹到的,由於 Spring 的 Bean 獲取須要知足不少種狀況。
  • 在學習的過程能夠優先按照 GetBean 流程圖進行梳理,以後對照源碼按步驟分析,這樣的過程幾乎會消耗你1~2天的時間,但整個過程學習完,基本也就對 GetBean 沒有什麼陌生了。
  • 學習幾乎就是一個慢慢磨的過程,就像走迷宮同樣,雖然有時候會走錯路,但那些錯了的路也是知識學習的一部分。在編程的學習中不僅是看結果,過程是更重要的,學會學習的方式更有意義。

6、系列推薦

相關文章
相關標籤/搜索