概述
前面我們介紹了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-init、default-merge、default-autowire、default-dependency-check、default-autowire-candidates、default-init-method、default-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)了,主要是針對AbstractBeanDefinition的methodOverride屬性進(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é)