BeanDefinition 在IOC的解析和注冊

概述

前面我們介紹了BeanDefinition的載入和解析的過程,將我們定義好的Bean資源文件載入并轉(zhuǎn)換成了Document對象,然后Document對象通過BeanDefinitionDocumentReader來解析,這些動作完成以后,用戶自定義的BeanDefinition信息已經(jīng)在IOC容器內(nèi)建立起了自己的數(shù)據(jù)結(jié)構(gòu),以及相應(yīng)的數(shù)據(jù)表示,但這些數(shù)據(jù)還不能在IOC容器中直接使用,需要在IOC容器中對這些BeanDefinition進(jìn)行注冊。這個注冊為IOC容器提供了更友好的使用方式。在DefaultListableBeanDactory中是使用一個Map對象載入并持有這些BeanDefinition的,代碼如下所示:

    /** Map of bean definition objects, keyed by bean name. */
    /**持有BeanDefinition的map容器**/
    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
源碼解析

1.核心流程時序圖:

核心流程時序圖

從源碼實(shí)現(xiàn)的角度我們可以分析得到上圖的調(diào)用關(guān)系。我們可以跟蹤源碼具體看一下注冊實(shí)現(xiàn),在DefaultListableBeanFactory中實(shí)現(xiàn)了BeanDefinitionRegistry的接口,這個接口的實(shí)現(xiàn)完成了BeanDefinition向容器注冊。注冊過程就是將解析得到的BeanDefinition設(shè)置到Map中去,但是如果遇到同名的BeanDefinition,進(jìn)行處理的時候需要依據(jù)allowBeanDefinitionOverriding的配置來完成。下面我們就BeanDefinition的注冊邏輯展開分析。

2.源代碼分析

  • registerBeanDefinitions核心流程代碼解析:

    
    /**
     * 通過解析Document解析注冊BeanDefinition
     * Register the bean definitions contained in the given DOM document.
     * Called by {@code loadBeanDefinitions}.
     * <p>Creates a new instance of the parser class and invokes
     * {@code registerBeanDefinitions} on it.
     * @param doc the DOM document
     * @param resource the resource descriptor (for context information)
     * @return the number of bean definitions found
     * @throws BeanDefinitionStoreException in case of parsing errors
     * @see #loadBeanDefinitions
     * @see #setDocumentReaderClass
     * @see BeanDefinitionDocumentReader#registerBeanDefinitions
     */
    public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
        // 獲取BeanDefinition的Document解析器
        BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
        // 獲取已經(jīng)注冊的BeanDefinition的個數(shù)
        int countBefore = getRegistry().getBeanDefinitionCount();
        // 創(chuàng)建XmlRederContext,解析Document并注冊BeanDefinition
        documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
        // 計(jì)算新注冊的BeanDefinition的數(shù)量
        return getRegistry().getBeanDefinitionCount() - countBefore;
    }
    
  • registerBeanDefinitions的處理邏輯解析:

    /**
     * This implementation parses bean definitions according to the "spring-beans" XSD (or DTD, historically).
     * document中element的解析并注冊BeanDefinition·
     * <p>Opens a DOM Document; then initializes the default settings
     * specified at the {@code <beans/>} level; then parses the contained bean definitions.
     */
    @Override
    public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
        this.readerContext = readerContext;
        doRegisterBeanDefinitions(doc.getDocumentElement());
    }
    
  • doRegisterBeanDefinitions處理邏輯解析

    
    /**
     * Register each bean definition within the given root {@code <beans/>} element.
     */
    @SuppressWarnings("deprecation")  // for Environment.acceptsProfiles(String...)
    protected void doRegisterBeanDefinitions(Element root) {
        // Any nested <beans> elements will cause recursion in this method. In
        // 從<beans />配置中注冊每一個bean,如果有嵌套的beans,那么遞歸執(zhí)行這個方法。
        // order to propagate and preserve <beans> default-* attributes correctly,
        // keep track of the current (parent) delegate, which may be null. Create
        // the new (child) delegate with a reference to the parent for fallback purposes,
        // then ultimately reset this.delegate back to its original (parent) reference.
        // this behavior emulates a stack of delegates without actually necessitating one.
        // 在遞歸的時候,跟蹤父級delegate,新的遞歸調(diào)用引用上個方法的delegate
        BeanDefinitionParserDelegate parent = this.delegate;
        //  創(chuàng)建 BeanDefinitionParserDelegate 對象,并進(jìn)行設(shè)置到 delegate
        this.delegate = createDelegate(getReaderContext(), root, parent);
        // 檢查 <beans /> 根標(biāo)簽的命名空間是否為空,或者是 http://www.springframework.org/schema/beans【1】
        if (this.delegate.isDefaultNamespace(root)) {
            // 處理 profile 屬性。可參見《Spring3自定義環(huán)境配置 <beans profile="">》 【2】
            String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
            if (StringUtils.hasText(profileSpec)) {
                String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
                        profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
                // We cannot use Profiles.of(...) since profile expressions are not supported
                // in XML config. See SPR-12458 for details.
                // 判定環(huán)境參數(shù)是否滿足,無效則不注冊
                if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
                                "] not matching: " + getReaderContext().getResource());
                    }
                    return;
                }
            }
        }
        // 解析前處理目前是空處理,可以繼承,由子類去實(shí)現(xiàn)
        preProcessXml(root);
        // 解析xml為BeanDefinition并向容器注冊生成的BeanDefinition【3】
        parseBeanDefinitions(root, this.delegate);
        // 解析后處理,目前為空執(zhí)行,子類可繼承處理
        postProcessXml(root);
        // 設(shè)置為最初的BeanDefinitionParserDelegate
        this.delegate = parent;
    }
    

    【1】 檢查<beans /> 根標(biāo)簽的命名空間是否為空,或者是 http://www.springframework.org/schema/beans
    【2】檢查beans標(biāo)簽的是否指定profile環(huán)境注冊,若profile參數(shù)是不滿足條件,則不注冊
    【3】解析element(<beans />)下的<bean/>元素并注冊到BeanDefinition的map容器中。
    說明:createDelegate方法執(zhí)行主要是創(chuàng)建代理,然后代理首先初始化一些默認(rèn)的屬性,DocumentDefaultsDefinition是存儲默認(rèn)配置的對象:default-lazy-initdefault-merge、default-autowire、default-dependency-checkdefault-autowire-candidates、default-init-methoddefault-destroy-method。

  • parseBeanDefinitions處理邏輯解析

    /**
     * Parse the elements at the root level in the document: "import", "alias", "bean".
     *
     * @param root the DOM root element of the document
     */
    protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
        // 如果該節(jié)點(diǎn)使用默認(rèn)命名空間,執(zhí)行默認(rèn)解析【1】
        if (delegate.isDefaultNamespace(root)) {
            // root節(jié)點(diǎn)下的子節(jié)點(diǎn)【2】
            NodeList nl = root.getChildNodes();
            for (int i = 0; i < nl.getLength(); i++) {
                Node node = nl.item(i);
                if (node instanceof Element) {
                    Element ele = (Element) node;
                    // 如果該節(jié)點(diǎn)使用默認(rèn)命名空間,執(zhí)行默認(rèn)解析【3】
                    if (delegate.isDefaultNamespace(ele)) {
                        parseDefaultElement(ele, delegate);
                    } else { // 如果該節(jié)點(diǎn)非默認(rèn)命名空間,執(zhí)行自定義解析【4】
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        } else {// 如果根節(jié)點(diǎn)非默認(rèn)命名空間,執(zhí)行自定義解析【5】
            delegate.parseCustomElement(root);
        }
    }
    

    【1】如果該節(jié)點(diǎn)使用默認(rèn)命名空間,執(zhí)行默認(rèn)解析
    【2】root節(jié)點(diǎn)下的子節(jié)點(diǎn)
    【3】如果該節(jié)點(diǎn)使用默認(rèn)命名空間,執(zhí)行默認(rèn)解析
    【4】如果該節(jié)點(diǎn)非默認(rèn)命名空間,執(zhí)行自定義解析
    【5】如果該節(jié)點(diǎn)非默認(rèn)命名空間,執(zhí)行自定義解析

  • parseDefaultElement處理邏輯解析

    private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
        // import標(biāo)簽
        if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
            importBeanDefinitionResource(ele);
            //  alias 解析
        } else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
            processAliasRegistration(ele);
            //bean 解析
        } else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
            processBeanDefinition(ele, delegate);
            // beans元素解析
        } else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
            //遞歸解析beans
            doRegisterBeanDefinitions(ele);
        }
    }
    
  • processBeanDefinition處理邏輯解析

    /**
     * Process the given bean element, parsing the bean definition and registering it with the registry.
     */
    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
        // 委托BeanDefinition類的parseBeanDefinitionElement方法進(jìn)行元素解析,返回Beandefinition 【1】
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if (bdHolder != null) {
            // 當(dāng)返回的bdHolder 不為空的情況下,若存在默認(rèn)標(biāo)簽的子節(jié)點(diǎn)下再有自定義屬性,還需要再次對自定義標(biāo)簽進(jìn)行解析.【2】
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
            try {
                // Register the final decorated instance.
                // 最終執(zhí)行注冊邏輯【3】
                BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
            } catch (BeanDefinitionStoreException ex) {
                getReaderContext().error("Failed to register bean definition with name '" +
                        bdHolder.getBeanName() + "'", ele, ex);
            }
            // Send registration event.
            // 下發(fā)注冊事件,通知相關(guān)的監(jiān)聽器,這個bean已經(jīng)加載完成【4】
            getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }
    }
    

    【1】委托BeanDefinition類的parseBeanDefinitionElement方法進(jìn)行元素解析,返回Beandefinition ,此時的bdHolder實(shí)例已經(jīng)包含了我們配置文件中的各種屬性了,例如 : class,name,id,alias
    【2】當(dāng)返回的bdHolder 不為空的情況下,若存在默認(rèn)標(biāo)簽的子節(jié)點(diǎn)下再有自定義屬性,還需要再次對自定義標(biāo)簽進(jìn)行解析.
    【3】最終執(zhí)行BeanDefinition注冊邏輯
    【4】下發(fā)注冊事件,通知相關(guān)的監(jiān)聽器,這個bean已經(jīng)加載完成

  • registryBeanDefinition的注冊邏輯分析

    從代碼上分析我們的registryBeanDefinition的最終執(zhí)行是在是通過public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry),注冊的過程是在解析xml過程中完成注冊邏輯的。

    //---------------------------------------------------------------------
    // Implementation of BeanDefinitionRegistry interface
    //---------------------------------------------------------------------
    // 注冊BeanDefinition
    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
           throws BeanDefinitionStoreException {
       // 校驗(yàn) beanName 與 beanDefinition 非空
       Assert.hasText(beanName, "Bean name must not be empty");
       Assert.notNull(beanDefinition, "BeanDefinition must not be null");
    
       if (beanDefinition instanceof AbstractBeanDefinition) {
           try {
               // 【1】 校驗(yàn)BeanDefinition,這也是注冊前的最后一次校驗(yàn)了,主要是對屬性 methodOverrides 進(jìn)行校驗(yàn)。
               ((AbstractBeanDefinition) beanDefinition).validate();
           } catch (BeanDefinitionValidationException ex) {
               throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                       "Validation of bean definition failed", ex);
           }
       }
       //【2】從緩存中獲取指定beanName的 BeanDefinition,主要 判斷bean name下是否已經(jīng)注冊過BeanDefinition
       BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
       //【3】如果改BenDefinition已經(jīng)注冊,如果不允許覆蓋的話,則拋出異常
       if (existingDefinition != null) {
           if (!isAllowBeanDefinitionOverriding()) {
               throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
           }
           // 當(dāng)前要注冊的BeanDefinition的role 大于 已經(jīng)注冊過的BeanDefinition 打印info 日志
           else if (existingDefinition.getRole() < beanDefinition.getRole()) {
               // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
               if (logger.isInfoEnabled()) {
                   logger.info("Overriding user-defined bean definition for bean '" + beanName +
                           "' with a framework-generated bean definition: replacing [" +
                           existingDefinition + "] with [" + beanDefinition + "]");
               }
           }
           // 當(dāng)前要注冊的BeanDefinition與已被覆蓋的BeanDefinition不是一個對象,打印Debug日志信息
           else if (!beanDefinition.equals(existingDefinition)) {
               if (logger.isDebugEnabled()) {
                   logger.debug("Overriding bean definition for bean '" + beanName +
                           "' with a different definition: replacing [" + existingDefinition +
                           "] with [" + beanDefinition + "]");
               }
           }
           // 打印 trace日志信息
           else {
               if (logger.isTraceEnabled()) {
                   logger.trace("Overriding bean definition for bean '" + beanName +
                           "' with an equivalent definition: replacing [" + existingDefinition +
                           "] with [" + beanDefinition + "]");
               }
           }
           // 覆蓋已經(jīng)注冊的bean信息
           this.beanDefinitionMap.put(beanName, beanDefinition);
       }
       // 【4】未注冊執(zhí)行注冊邏輯
       else {
           // 判斷Bean的創(chuàng)建階段是否已經(jīng)開啟,開啟的話需要對beanDefinitionMap進(jìn)行線程保護(hù)
           if (hasBeanCreationStarted()) {
               // Cannot modify startup-time collection elements anymore (for stable iteration)
               // beanDefinitionMap為全局變量,加鎖保護(hù),防止創(chuàng)建階段和注冊階段的并發(fā)問題
               synchronized (this.beanDefinitionMap) {
                   // 添加到BeanDefinition的map 容器中
                   this.beanDefinitionMap.put(beanName, beanDefinition);
                   // 添加BeanName到 beanDefinitionNames中去(beanDefinitionNames初始化限制了大小為256,所以變更的時候需要引入一個中間變量-主要是擴(kuò)容問題)
                   List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
                   // 更新最新的beanDefinitionNames
                   updatedDefinitions.addAll(this.beanDefinitionNames);
                   updatedDefinitions.add(beanName);
                   this.beanDefinitionNames = updatedDefinitions;
                   // 從 manualSingletonNames 移除 beanName
                   removeManualSingletonName(beanName);
               }
           } else {
               // Still in startup registration phase
               // 添加到 BeanDefinition 到 beanDefinitionMap 中。
               this.beanDefinitionMap.put(beanName, beanDefinition);
               // 添加 beanName 到 beanDefinitionNames 中
               this.beanDefinitionNames.add(beanName);
               //  從 manualSingletonNames 移除 beanName
               removeManualSingletonName(beanName);
           }
           this.frozenBeanDefinitionNames = null;
       }
       // 【5】重新設(shè)置beanName對應(yīng)的緩存
       if (existingDefinition != null || containsSingleton(beanName)) {
           resetBeanDefinition(beanName);
       }
    }
    
    

    【1】對BeanDefinition進(jìn)行校驗(yàn),這也是注冊過程中最后一次校驗(yàn)了,主要是針對AbstractBeanDefinitionmethodOverride屬性進(jìn)行校驗(yàn)。
    【2】根據(jù)beanName從緩存中獲取BeanDefinition。
    【3】如果緩存中已經(jīng)存在,則根據(jù)allowBeanDefinitionOverriding標(biāo)簽判斷是否允許覆蓋,如果不允許覆蓋,則拋出BeanDefinitionStoreException異常。
    【4】若緩存中沒有beanName 的BeanDefinition對象,則判斷當(dāng)前階段是否已經(jīng)開始了Bean的創(chuàng)建階段,如果是則對僅限并發(fā)保護(hù),對BeanDefinitionMap進(jìn)行加鎖并發(fā)控制。否則直接設(shè)置即可。
    【5】若緩存存在改beanName或者單例bean集合中存在該beanName,則調(diào)用#resetBeanDefinition(beanName)方法,充值BeanDefinition緩存。

    整個階段的核心流程其實(shí)就是對beanDefinitionMap的操作,只要核心在于this.beanDefinitionMap.put(beanName, beanDefinition)方法,而BeanDefinition的存儲其實(shí)就是定義了個map,key為beanName,value為BeanDefinition。

小結(jié)
BeanDefinition解析注冊詳細(xì)流程圖

微信公眾號
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容