概述
前面我們介紹了BeanDefinition的載入和解析的過程,將我們定義好的Bean資源文件載入并轉換成了Document對象,然后Document對象通過BeanDefinitionDocumentReader來解析,這些動作完成以后,用戶自定義的BeanDefinition信息已經在IOC容器內建立起了自己的數據結構,以及相應的數據表示,但這些數據還不能在IOC容器中直接使用,需要在IOC容器中對這些BeanDefinition進行注冊。這個注冊為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.核心流程時序圖:
從源碼實現的角度我們可以分析得到上圖的調用關系。我們可以跟蹤源碼具體看一下注冊實現,在
DefaultListableBeanFactory
中實現了BeanDefinitionRegistry
的接口,這個接口的實現完成了BeanDefinition
向容器注冊。注冊過程就是將解析得到的BeanDefinition
設置到Map中去,但是如果遇到同名的BeanDefinition
,進行處理的時候需要依據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(); // 獲取已經注冊的BeanDefinition的個數 int countBefore = getRegistry().getBeanDefinitionCount(); // 創建XmlRederContext,解析Document并注冊BeanDefinition documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); // 計算新注冊的BeanDefinition的數量 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,那么遞歸執行這個方法。 // 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,新的遞歸調用引用上個方法的delegate BeanDefinitionParserDelegate parent = this.delegate; // 創建 BeanDefinitionParserDelegate 對象,并進行設置到 delegate this.delegate = createDelegate(getReaderContext(), root, parent); // 檢查 <beans /> 根標簽的命名空間是否為空,或者是 http://www.springframework.org/schema/beans【1】 if (this.delegate.isDefaultNamespace(root)) { // 處理 profile 屬性??蓞⒁姟禨pring3自定義環境配置 <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. // 判定環境參數是否滿足,無效則不注冊 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; } } } // 解析前處理目前是空處理,可以繼承,由子類去實現 preProcessXml(root); // 解析xml為BeanDefinition并向容器注冊生成的BeanDefinition【3】 parseBeanDefinitions(root, this.delegate); // 解析后處理,目前為空執行,子類可繼承處理 postProcessXml(root); // 設置為最初的BeanDefinitionParserDelegate this.delegate = parent; }
【1】 檢查
<beans />
根標簽的命名空間是否為空,或者是http://www.springframework.org/schema/beans
【2】檢查beans標簽的是否指定profile環境注冊,若profile參數是不滿足條件,則不注冊
【3】解析element(<beans />
)下的<bean/>
元素并注冊到BeanDefinition的map容器中。
說明:createDelegate
方法執行主要是創建代理,然后代理首先初始化一些默認的屬性,DocumentDefaultsDefinition是存儲默認配置的對象: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) { // 如果該節點使用默認命名空間,執行默認解析【1】 if (delegate.isDefaultNamespace(root)) { // root節點下的子節點【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; // 如果該節點使用默認命名空間,執行默認解析【3】 if (delegate.isDefaultNamespace(ele)) { parseDefaultElement(ele, delegate); } else { // 如果該節點非默認命名空間,執行自定義解析【4】 delegate.parseCustomElement(ele); } } } } else {// 如果根節點非默認命名空間,執行自定義解析【5】 delegate.parseCustomElement(root); } }
【1】如果該節點使用默認命名空間,執行默認解析
【2】root節點下的子節點
【3】如果該節點使用默認命名空間,執行默認解析
【4】如果該節點非默認命名空間,執行自定義解析
【5】如果該節點非默認命名空間,執行自定義解析 -
parseDefaultElement處理邏輯解析
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { // import標簽 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方法進行元素解析,返回Beandefinition 【1】 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { // 當返回的bdHolder 不為空的情況下,若存在默認標簽的子節點下再有自定義屬性,還需要再次對自定義標簽進行解析.【2】 bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // Register the final decorated instance. // 最終執行注冊邏輯【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. // 下發注冊事件,通知相關的監聽器,這個bean已經加載完成【4】 getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } }
【1】委托BeanDefinition類的parseBeanDefinitionElement方法進行元素解析,返回Beandefinition ,此時的bdHolder實例已經包含了我們配置文件中的各種屬性了,例如 : class,name,id,alias
【2】當返回的bdHolder 不為空的情況下,若存在默認標簽的子節點下再有自定義屬性,還需要再次對自定義標簽進行解析.
【3】最終執行BeanDefinition注冊邏輯
【4】下發注冊事件,通知相關的監聽器,這個bean已經加載完成
-
registryBeanDefinition的注冊邏輯分析
從代碼上分析我們的registryBeanDefinition的最終執行是在是通過
public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
,注冊的過程是在解析xml過程中完成注冊邏輯的。//--------------------------------------------------------------------- // Implementation of BeanDefinitionRegistry interface //--------------------------------------------------------------------- // 注冊BeanDefinition @Override public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { // 校驗 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】 校驗BeanDefinition,這也是注冊前的最后一次校驗了,主要是對屬性 methodOverrides 進行校驗。 ((AbstractBeanDefinition) beanDefinition).validate(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", ex); } } //【2】從緩存中獲取指定beanName的 BeanDefinition,主要 判斷bean name下是否已經注冊過BeanDefinition BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName); //【3】如果改BenDefinition已經注冊,如果不允許覆蓋的話,則拋出異常 if (existingDefinition != null) { if (!isAllowBeanDefinitionOverriding()) { throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition); } // 當前要注冊的BeanDefinition的role 大于 已經注冊過的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 + "]"); } } // 當前要注冊的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 + "]"); } } // 覆蓋已經注冊的bean信息 this.beanDefinitionMap.put(beanName, beanDefinition); } // 【4】未注冊執行注冊邏輯 else { // 判斷Bean的創建階段是否已經開啟,開啟的話需要對beanDefinitionMap進行線程保護 if (hasBeanCreationStarted()) { // Cannot modify startup-time collection elements anymore (for stable iteration) // beanDefinitionMap為全局變量,加鎖保護,防止創建階段和注冊階段的并發問題 synchronized (this.beanDefinitionMap) { // 添加到BeanDefinition的map 容器中 this.beanDefinitionMap.put(beanName, beanDefinition); // 添加BeanName到 beanDefinitionNames中去(beanDefinitionNames初始化限制了大小為256,所以變更的時候需要引入一個中間變量-主要是擴容問題) 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】重新設置beanName對應的緩存 if (existingDefinition != null || containsSingleton(beanName)) { resetBeanDefinition(beanName); } }
【1】對
BeanDefinition
進行校驗,這也是注冊過程中最后一次校驗了,主要是針對AbstractBeanDefinition
的methodOverride
屬性進行校驗。
【2】根據beanName從緩存中獲取BeanDefinition。
【3】如果緩存中已經存在,則根據allowBeanDefinitionOverriding標簽判斷是否允許覆蓋,如果不允許覆蓋,則拋出BeanDefinitionStoreException
異常。
【4】若緩存中沒有beanName 的BeanDefinition
對象,則判斷當前階段是否已經開始了Bean的創建階段,如果是則對僅限并發保護,對BeanDefinitionMap
進行加鎖并發控制。否則直接設置即可。
【5】若緩存存在改beanName或者單例bean集合中存在該beanName,則調用#resetBeanDefinition(beanName)
方法,充值BeanDefinition緩存。整個階段的核心流程其實就是對beanDefinitionMap的操作,只要核心在于
this.beanDefinitionMap.put(beanName, beanDefinition)
方法,而BeanDefinition的存儲其實就是定義了個map,key為beanName,value為BeanDefinition。
小結