本系列所有基於 Spring 5.2.2.BUILD-SNAPSHOT
版本。由於 Spring 整個體系太過於龐大,因此只會進行關鍵部分的源碼解析。java
本篇文章主要介紹 Spring IoC 容器怎麼解析默認標籤的。node
所謂的默認標籤就是 import
、alias
、bean
、beans
這四個標籤。git
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)) { doRegisterBeanDefinitions(ele); } }
上面 parseDefaultElement
方法中對 bean 標籤的處理方法 processBeanDefinition
最爲重要,下面來着重分析一下。github
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { // 將ele解析成BeanDefinitionHolder,見下文詳解 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { // 若存在默認標籤下的子節點下再也不有自定義屬性,須要再次對自定義標籤再進行解析(基本不用,不作深刻分析) bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // 註冊最終的BeanDefinition,見下文詳解 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex); } // 發出響應事件,通知相關監聽器,這個bean已經註冊完 getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } }
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) { // 解析元素,封裝成BeanDefinitionHolder return parseBeanDefinitionElement(ele, null); } public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) { // 獲取id屬性 String id = ele.getAttribute(ID_ATTRIBUTE); // 獲取name屬性 String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); List<String> aliases = new ArrayList<>(); // 將name屬性全部的名稱按照逗號或者分號(,;),分割成數組放入別名集合aliases if (StringUtils.hasLength(nameAttr)) { String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS); aliases.addAll(Arrays.asList(nameArr)); } // beanName默認使用id String beanName = id; // 沒有指定id屬性 && 指定了name屬性 if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) { // 若是沒有指定id,beanName等於第一個別名,剩下的依然做爲別名使用 beanName = aliases.remove(0); } if (containingBean == null) { // 驗證beanName和aliases是否在同一個<beans>下已經存在 checkNameUniqueness(beanName, aliases, ele); } // 將元素解析成GenericBeanDefinition AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean); if (beanDefinition != null) { // 若是不存在beanName會根據Spring的命名規則生成一個 if (!StringUtils.hasText(beanName)) { try { if (containingBean != null) { beanName = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, this.readerContext.getRegistry(), true); } else { beanName = this.readerContext.generateBeanName(beanDefinition); String beanClassName = beanDefinition.getBeanClassName(); if (beanClassName != null && beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() && !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) { aliases.add(beanClassName); } } } catch (Exception ex) { error(ex.getMessage(), ele); return null; } } String[] aliasesArray = StringUtils.toStringArray(aliases); // 用beanDefinition和beanName以及aliasesArray構建BeanDefinitionHolder return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray); } return null; } public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean) { this.parseState.push(new BeanEntry(beanName)); String className = null; // 獲取class屬性 if (ele.hasAttribute(CLASS_ATTRIBUTE)) { className = ele.getAttribute(CLASS_ATTRIBUTE).trim(); } String parent = null; // 獲取parent屬性 if (ele.hasAttribute(PARENT_ATTRIBUTE)) { parent = ele.getAttribute(PARENT_ATTRIBUTE); } try { // 建立用於承載屬性的AbstractBeanDefinition類型的GenericBeanDefinition AbstractBeanDefinition bd = createBeanDefinition(className, parent); // 解析默認bean的各類屬性,見下文詳解 parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); // 提取description bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT)); // 解析元數據,見下文詳解 parseMetaElements(ele, bd); // 解析lookup-method屬性,不多使用,不具體介紹 parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); // 解析replaced-method屬性,不多使用,不具體介紹 parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); // 解析constructor-arg屬性,見下文詳解 parseConstructorArgElements(ele, bd); // 解析property屬性,見下文詳解 parsePropertyElements(ele, bd); // 解析qualifier屬性,見下文詳解 parseQualifierElements(ele, bd); bd.setResource(this.readerContext.getResource()); bd.setSource(extractSource(ele)); return bd; } // 省略異常處理... finally { this.parseState.pop(); } return null; }
上面方法中的 BeanDefinitionReaderUtils.generateBeanName()
方法會爲 bean
生成一個默認的名稱,主要規則以下:spring
bean
的全類名,例如 com.leisurexi.ioc.domain.User
;若是 bean
的 parent
不爲空那麼 bean
的名稱爲 parentName
加上 $child
,例如 user
的 parent
是名稱爲 parentUser
的 bean
,那麼當 user
未指定 beanName
時會其生成一個 parentUser$child
的名稱;若是 bean
的 parent
爲空但 factory-bean
屬性不爲空,那就用該名稱加上 $created
爲其生成名稱。parent
和 factory-bean
屬性,那麼若是是內嵌 bean
則用全類名加上 #
和轉換爲十六進制字符串的 hashcode
拼成的字符串當作名稱;不是內嵌 bean
就用全類名加上 #
和數字當作名稱,如第一個 User
類型的自動生成的名稱爲 com.leisurexi.ioc.domain.User#0
,第二個就是 com.leisurexi.ioc.domain.User#1
。咱們這邊能夠簡單看一下 BeanDefinitionHolder
的屬性,以下:數組
public class BeanDefinitionHolder implements BeanMetadataElement { // bean 的定義元信息 private final BeanDefinition beanDefinition; // bean 的名稱 private final String beanName; // bean 的別名數組 @Nullable private final String[] aliases; // 省略其它代碼... }
public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName, @Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) { // 解析singleton屬性 if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) { // singleton屬性已經不支持了,使用了會直接拋出異常,請使用scope屬性替代 error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele); } // 解析scope屬性 else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) { bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE)); } // 若是是內嵌bean,則使用上級bean的scope值 else if (containingBean != null) { bd.setScope(containingBean.getScope()); } // 解析abstract屬性 if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) { bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE))); } // 解析lazy屬性 String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE); // 若沒有設置或者設置成其餘字符都會被設置爲默認值false if (isDefaultValue(lazyInit)) { lazyInit = this.defaults.getLazyInit(); } bd.setLazyInit(TRUE_VALUE.equals(lazyInit)); // 解析autowire屬性 String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE); bd.setAutowireMode(getAutowireMode(autowire)); // 解析depends-on屬性 if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) { String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE); bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS)); } // 解析autowire-candidate屬性,該屬性爲false表明該bean不會被選爲依賴注入的對象,默認爲true String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE); if (isDefaultValue(autowireCandidate)) { String candidatePattern = this.defaults.getAutowireCandidates(); if (candidatePattern != null) { String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern); bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName)); } } else { bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate)); } // 解析primary屬性 if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) { bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE))); } // 解析init-method屬性 if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) { String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE); bd.setInitMethodName(initMethodName); } // 若是bean沒有指定init-method屬性,但beans標籤指定了default-init-method屬性,則會使用該屬性 else if (this.defaults.getInitMethod() != null) { bd.setInitMethodName(this.defaults.getInitMethod()); bd.setEnforceInitMethod(false); } // 解析destroy-method屬性 if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) { String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE); bd.setDestroyMethodName(destroyMethodName); } // 若是bean沒有指定destroy-method屬性,但beans標籤指定了default-destroy-method屬性,則會使用該屬性 else if (this.defaults.getDestroyMethod() != null) { bd.setDestroyMethodName(this.defaults.getDestroyMethod()); bd.setEnforceDestroyMethod(false); } // 解析factory-method屬性 if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) { bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE)); } // 解析factory-bean屬性 if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) { bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE)); } return bd; }
上面方法完成了對全部 bean
標籤屬性的解析。值得注意的地方是若是同時指定了 bean
標籤的 init-method
和 beans
標籤的 default-init-method
屬性,那麼優先使用前者,destory-mehtod
標籤也是同樣。緩存
你們能夠去看一下
AbstractBeanDefinition
中定義的屬性就一目瞭然了,這裏限於篇幅緣由就不展現了。安全
public void parseConstructorArgElements(Element beanEle, BeanDefinition bd) { // 獲取全部子節點 NodeList nl = beanEle.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); // 提取 constructor-arg if (isCandidateElement(node) && nodeNameEquals(node, CONSTRUCTOR_ARG_ELEMENT)) { // 解析 constructor-arg parseConstructorArgElement((Element) node, bd); } } } // <constructor-arg index="0" type="" value=""/> public void parseConstructorArgElement(Element ele, BeanDefinition bd) { // 提取 index 屬性 String indexAttr = ele.getAttribute(INDEX_ATTRIBUTE); // 提取 type 屬性 String typeAttr = ele.getAttribute(TYPE_ATTRIBUTE); // 提取 name 屬性 String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); // index 不爲空 if (StringUtils.hasLength(indexAttr)) { try { // 轉換爲 int 類型 int index = Integer.parseInt(indexAttr); if (index < 0) { error("'index' cannot be lower than 0", ele); } else { try { this.parseState.push(new ConstructorArgumentEntry(index)); // 解析屬性值,見下文詳解 Object value = parsePropertyValue(ele, bd, null); // 使用 ConstructorArgumentValues.ValueHolder 類型來封裝解析出來的元素 ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value); // 若是 type 不爲空,設置 ValueHolder 的 type if (StringUtils.hasLength(typeAttr)) { valueHolder.setType(typeAttr); } // 若是 name 不爲空,設置 ValueHolder 的 name if (StringUtils.hasLength(nameAttr)) { valueHolder.setName(nameAttr); } valueHolder.setSource(extractSource(ele)); // 判斷 index 是否重複,重複則拋出異常 if (bd.getConstructorArgumentValues().hasIndexedArgumentValue(index)) { error("Ambiguous constructor-arg entries for index " + index, ele); } // 將 index 和 valueHolder 以 key-value的形式 添加到 BeanDefinition 的 ConstructorArgumentValues 當中 else { bd.getConstructorArgumentValues().addIndexedArgumentValue(index, valueHolder); } } finally { this.parseState.pop(); } } } catch (NumberFormatException ex) { error("Attribute 'index' of tag 'constructor-arg' must be an integer", ele); } } else { try { // 這裏就是 constructor-arg 標籤中沒有指定 index 屬性 this.parseState.push(new ConstructorArgumentEntry()); Object value = parsePropertyValue(ele, bd, null); ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value); if (StringUtils.hasLength(typeAttr)) { valueHolder.setType(typeAttr); } if (StringUtils.hasLength(nameAttr)) { valueHolder.setName(nameAttr); } valueHolder.setSource(extractSource(ele)); // 將 valueHolder 添加 BeanDefinition 的 GenericArgumentValue 中 // 這裏和上面的 IndexedArgumentValue 相似,只不過上面是 Map,這裏是 List bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder); } finally { this.parseState.pop(); } } }
上面代碼首先提取 constructor-arg
標籤中必要的屬性 (index
、type
、name
)。框架
index
屬性:
constructor-arg
的子元素。ConstructorArgumentsValues.ValueHolder
類型來封裝解析出來的元素。type
、name
和 index
屬性一併封裝在 ConstructorArgumentsValues.ValueHolder
類型中,並添加到當前 BeanDefinition
的 ConstructorArgumentValues
中的 LinkedHashMap
類型的屬性indexedArgumentValues
中。index
屬性:
constructor-arg
的子元素。ConstructorArgumentsValues.ValueHolder
類型來封裝解析出來的元素。type
、name
和 index
屬性一併封裝在 ConstructorArgumentsValues.ValueHolder
類型中,並添加到當前 BeanDefinition
的 ConstructorArgumentValues
中的 ArrayList
類型的屬性genericArgumentValues
中。public Object parsePropertyValue(Element ele, BeanDefinition bd, @Nullable String propertyName) { String elementName = (propertyName != null ? "<property> element for property '" + propertyName + "'" : "<constructor-arg> element"); // 獲取全部子節點,例如list、map等 NodeList nl = ele.getChildNodes(); Element subElement = null; for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); // 跳過 description 或者 meta 不處理 if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) && !nodeNameEquals(node, META_ELEMENT)) { // Child element is what we're looking for. if (subElement != null) { error(elementName + " must not contain more than one sub-element", ele); } else { subElement = (Element) node; } } } // 提取 ref 屬性 boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE); // 提取 value 屬性 boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE); // 若是同時有 ref 和 value 屬性 || 有 ref 或 value 屬性同時又有子元素,拋出異常 if ((hasRefAttribute && hasValueAttribute) || ((hasRefAttribute || hasValueAttribute) && subElement != null)) { error(elementName + " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele); } // 只有 ref 屬性,使用 RuntimeBeanReference 封裝對應的 ref 名稱 (該 ref 值指向另外一個 bean 的 beanName) // RuntimeBeanReference 起到佔位符的做用, ref 指向的 beanName 將在運行時被解析成真正的 bean 實例引用 if (hasRefAttribute) { String refName = ele.getAttribute(REF_ATTRIBUTE); if (!StringUtils.hasText(refName)) { error(elementName + " contains empty 'ref' attribute", ele); } RuntimeBeanReference ref = new RuntimeBeanReference(refName); ref.setSource(extractSource(ele)); return ref; } // 只有 value 屬性,使用 TypedStringValue 封裝 else if (hasValueAttribute) { TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE)); valueHolder.setSource(extractSource(ele)); return valueHolder; } else if (subElement != null) { // 解析子元素 return parsePropertySubElement(subElement, bd); } else { // 沒有子元素,也沒有 ref 和 value,直接拋出異常 error(elementName + " must specify a ref or value", ele); return null; } } public Object parsePropertySubElement(Element ele, @Nullable BeanDefinition bd) { return parsePropertySubElement(ele, bd, null); } public Object parsePropertySubElement(Element ele, @Nullable BeanDefinition bd, @Nullable String defaultValueType) { // 校驗是否爲默認的命名空間,若是不是則走解析自定義節點代碼 if (!isDefaultNamespace(ele)) { return parseNestedCustomElement(ele, bd); } // 解析 bean 節點 else if (nodeNameEquals(ele, BEAN_ELEMENT)) { BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd); if (nestedBd != null) { nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd); } return nestedBd; } // 解析 ref 節點 else if (nodeNameEquals(ele, REF_ELEMENT)) { String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE); boolean toParent = false; if (!StringUtils.hasLength(refName)) { // A reference to the id of another bean in a parent context. refName = ele.getAttribute(PARENT_REF_ATTRIBUTE); toParent = true; if (!StringUtils.hasLength(refName)) { error("'bean' or 'parent' is required for <ref> element", ele); return null; } } if (!StringUtils.hasText(refName)) { error("<ref> element contains empty target attribute", ele); return null; } RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent); ref.setSource(extractSource(ele)); return ref; } // 解析 idref 節點 else if (nodeNameEquals(ele, IDREF_ELEMENT)) { return parseIdRefElement(ele); } // 解析 value 節點 else if (nodeNameEquals(ele, VALUE_ELEMENT)) { return parseValueElement(ele, defaultValueType); } // 解析 null 節點 else if (nodeNameEquals(ele, NULL_ELEMENT)) { TypedStringValue nullHolder = new TypedStringValue(null); nullHolder.setSource(extractSource(ele)); return nullHolder; } // 解析 array 節點 else if (nodeNameEquals(ele, ARRAY_ELEMENT)) { return parseArrayElement(ele, bd); } // 解析 list 節點 else if (nodeNameEquals(ele, LIST_ELEMENT)) { return parseListElement(ele, bd); } // 解析 set 節點 else if (nodeNameEquals(ele, SET_ELEMENT)) { return parseSetElement(ele, bd); } // 解析 map 節點 else if (nodeNameEquals(ele, MAP_ELEMENT)) { return parseMapElement(ele, bd); } // 解析 props 節點 else if (nodeNameEquals(ele, PROPS_ELEMENT)) { return parsePropsElement(ele); } // 未知屬性,拋出異常 else { error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele); return null; } }
從上面的代碼來看,對構造函數中屬性元素的解析,步驟以下:dom
description
或者 meta
。constructor-arg
上的 ref
和 value
屬性,以便於根據規則驗證正確性。其規則爲在 constructor-arg
上不存在如下狀況:
ref
和 value
屬性。ref
或者 value
屬性,而且又有子元素。public void parsePropertyElements(Element beanEle, BeanDefinition bd) { // 獲取全部子節點 NodeList nl = beanEle.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) { // 解析 property 節點 parsePropertyElement((Element) node, bd); } } } // 這裏是解析 property 標籤,<property name="..." value="..."/> public void parsePropertyElement(Element ele, BeanDefinition bd) { // 獲取 name 屬性 String propertyName = ele.getAttribute(NAME_ATTRIBUTE); // name 爲空,拋出異常 if (!StringUtils.hasLength(propertyName)) { error("Tag 'property' must have a 'name' attribute", ele); return; } this.parseState.push(new PropertyEntry(propertyName)); try { // 出現兩個 name 相同的拋出異常 if (bd.getPropertyValues().contains(propertyName)) { error("Multiple 'property' definitions for property '" + propertyName + "'", ele); return; } // 解析屬性值,跟構造器解析同樣 Object val = parsePropertyValue(ele, bd, propertyName); // 用 name 和 val 封裝成 PropertyValue PropertyValue pv = new PropertyValue(propertyName, val); // 解析元數據,跟 beans 標籤內的 meta 同樣 parseMetaElements(ele, pv); pv.setSource(extractSource(ele)); // 添加到 BeanDefinition 的 PropertyValues 屬性中 bd.getPropertyValues().addPropertyValue(pv); } finally { this.parseState.pop(); } }
上面方法主要是遍歷 property
節點,而後解析屬性值封裝成 PropertyValue
添加到 BeanDefinition
的 PropertyValues
中。
注意:
property
標明的屬性必需有set
方法不然在賦值階段會拋出異常。
public void parseQualifierElements(Element beanEle, AbstractBeanDefinition bd) { // 獲取子節點 NodeList nl = beanEle.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (isCandidateElement(node) && nodeNameEquals(node, QUALIFIER_ELEMENT)) { // 解析 qualifier 節點 parseQualifierElement((Element) node, bd); } } } public void parseQualifierElement(Element ele, AbstractBeanDefinition bd) { // 提取 type String typeName = ele.getAttribute(TYPE_ATTRIBUTE); // type 爲空拋出異常 if (!StringUtils.hasLength(typeName)) { error("Tag 'qualifier' must have a 'type' attribute", ele); return; } this.parseState.push(new QualifierEntry(typeName)); try { AutowireCandidateQualifier qualifier = new AutowireCandidateQualifier(typeName); qualifier.setSource(extractSource(ele)); // 提取 value String value = ele.getAttribute(VALUE_ATTRIBUTE); // value 不爲空,設置到 AutowireCandidateQualifier 的 attribute 中 if (StringUtils.hasLength(value)) { qualifier.setAttribute(AutowireCandidateQualifier.VALUE_KEY, value); } // 獲取子節點 NodeList nl = ele.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); // 若是是有 attribute 節點,進行解析,提取值放入到 AutowireCandidateQualifier 的MetadataAttribute 中 if (isCandidateElement(node) && nodeNameEquals(node, QUALIFIER_ATTRIBUTE_ELEMENT)) { Element attributeEle = (Element) node; String attributeName = attributeEle.getAttribute(KEY_ATTRIBUTE); String attributeValue = attributeEle.getAttribute(VALUE_ATTRIBUTE); if (StringUtils.hasLength(attributeName) && StringUtils.hasLength(attributeValue)) { BeanMetadataAttribute attribute = new BeanMetadataAttribute(attributeName, attributeValue); attribute.setSource(extractSource(attributeEle)); qualifier.addMetadataAttribute(attribute); } else { error("Qualifier 'attribute' tag must have a 'name' and 'value'", attributeEle); return; } } } // 設置 BeanDefinition 的 qualifier bd.addQualifier(qualifier); } finally { this.parseState.pop(); } }
對於 qualifier
元素的獲取,咱們大多數接觸的更可能是註解的形式,在使用 Spring 框架中進行自動注入時,Spring 容器中匹配的候選 Bean
必需有且只有一個。若是存在多個類型相同的 Bean
,且按照類型注入時,Spring 容許經過 qualifier
指定注入 Bean
的名稱,這樣歧義就消除了。
public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { // Register bean definition under primary name. // 獲取 beanName String beanName = definitionHolder.getBeanName(); // 以 key-value 的形式註冊,key 爲 beanName,value 爲 BeanDefinition。見下文詳解 registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); // Register aliases for bean name, if any. // 註冊 bean 的別名 String[] aliases = definitionHolder.getAliases(); if (aliases != null) { for (String alias : aliases) { // 以 key-value 的形式註冊 bean 的別名,key 爲別名,value 爲 beanName。見下文詳解 registry.registerAlias(beanName, alias); } } } // DefaultListableBeanFactory.java public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { Assert.hasText(beanName, "Bean name must not be empty"); Assert.notNull(beanDefinition, "BeanDefinition must not be null"); if (beanDefinition instanceof AbstractBeanDefinition) { try { // 驗證 Bean 的格式是否正確 ((AbstractBeanDefinition) beanDefinition).validate(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", ex); } } BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName); // 這裏判斷 BeanDefinition 是否存在 if (existingDefinition != null) { // 這裏就是若是 Bean 定義以及存在,判斷是否能夠覆蓋,默認是能夠的 // Spring Boot 2.1開始這裏會手動設置 allowBeanDefinitionOverriding 的值爲 false if (!isAllowBeanDefinitionOverriding()) { throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition); } // 將 beanName 和 BeanDefinition 以 key-value 形式放入beanDefinitionMap 緩存中 this.beanDefinitionMap.put(beanName, beanDefinition); } else { // bean 是否已經開始建立 if (hasBeanCreationStarted()) { synchronized (this.beanDefinitionMap) { // 將 beanName 和 BeanDefinition 以 key-value 形式放入beanDefinitionMap 緩存中 this.beanDefinitionMap.put(beanName, beanDefinition); // 這裏將 beanDefinitionNames 寫時複製一份,相似於 CopyOnWriteArrayList List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1); updatedDefinitions.addAll(this.beanDefinitionNames); updatedDefinitions.add(beanName); this.beanDefinitionNames = updatedDefinitions; // 從單例 Bean 註冊名稱列表中刪除當前 beanName removeManualSingletonName(beanName); } } // bean 不在建立狀態中 else { // Still in startup registration phase this.beanDefinitionMap.put(beanName, beanDefinition); // 由於 ConcurrentHashMap 是無序的,這裏將 beanName 放入 ArrayList,記錄註冊順序 this.beanDefinitionNames.add(beanName); // 從單例 Bean 註冊名稱列表中刪除當前 beanName removeManualSingletonName(beanName); } this.frozenBeanDefinitionNames = null; } // 若是存在相同的 beanName 的 BeanDefinition,或者 beanName 已經存在單例對象,則將該 beanName 對應的緩存信息、單例對象清除,由於這些對象都是由老的 BeanDefinition 建立的,須要被覆蓋掉。再用新的 BeanDefinition 來建立這些緩存和單例對象 if (existingDefinition != null || containsSingleton(beanName)) { resetBeanDefinition(beanName); } } // SimpleAliasRegistry.java public void registerAlias(String name, String alias) { Assert.hasText(name, "'name' must not be empty"); Assert.hasText(alias, "'alias' must not be empty"); synchronized (this.aliasMap) { // 若是別名和 beanName 相同,從緩存中移除 if (alias.equals(name)) { this.aliasMap.remove(alias); } else { String registeredName = this.aliasMap.get(alias); // 若是別名以及註冊過,直接返回 if (registeredName != null) { if (registeredName.equals(name)) { // An existing alias - no need to re-register return; } // 若是不容許覆蓋,拋出異常 if (!allowAliasOverriding()) { throw new IllegalStateException("Cannot define alias '" + alias + "' for name '" + name + "': It is already registered for name '" + registeredName + "'."); } } // 檢查 name 和 alias 是否存在循環引用。例如 A 的別名爲 B,B的別名爲A checkForAliasCircle(name, alias); // 將 alias 和 name 以 key-value 對放入到 aliasMap 中,進行緩存 this.aliasMap.put(alias, name); } } } }
上面代碼有兩個變量比較重要 beanDefinitionMap
和 beanDefinitionNames
,下面代碼是這兩個屬性在 DefaultListableBeanFactory
中的定義:
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable { // 緩存 BeanDefinition 的 Map,key 爲 beanName,value 爲 BeanDefinition private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256); // 保存 BeanDefinition 的註冊順序,保存的是 beanName private volatile List<String> beanDefinitionNames = new ArrayList<>(256); }
上面方法的主要流程以下:
若是 BeanDefinition
是 AbstractBeanDefinition
類型,驗證 Bean
的格式是否正確。
此次效驗主要是對於
AbstractBeanDefinition
屬性中的methodOverrides
的校驗,校驗methodOverrides
是否與 工廠方法 並存或者methodOverrides
中的方法根本不存在。
判斷該 beanName
的 BeanDefinition
是否已經註冊過;若是存在判斷是否容許覆蓋,容許的話直接替換,不容許直接拋出異常。
默認的狀況下是容許的,可是在 Spring Boot 2.1 開始這裏會手動的設置爲不容許。
beanName
對應的 BeanDefinition
之前沒有註冊過,判斷 bean
是否已經開始建立;若是在建立中對 beanDefinitionMap
進行加鎖 (這裏雖然 beanDefinitionMap
是線程安全的 ConcurrentHashMap
,單個操做是線程安全的但多個操做不是,因此這裏手動加鎖),而後將 beanName
和 BeanDefinition
以 key-value
形式放入 beanDefinitionMap
緩存中,而後寫時複製一份 beanDefinitionNames
,將 beaName
緩存進去,記錄 bean
的註冊順序;若是不在建立中直接將 BeanDefinition
和 beanName
分別放入 beanDefinitionMap
和 beanDefinitionNames
中。
最後判斷若是 BeanDefinition
已經註冊過,或者 beanName
已經存在單例對象,則將該 beanName
對應的緩存信息、單例對象清除,由於這些對象都是由老的 BeanDefinition
建立的,須要被覆蓋掉。再用新的 BeanDefinition
來建立這些緩存和單例對象。
本文主要介紹了 Spring 對 XML 文件中 <bean>
標籤的解析,咱們能夠從新梳理一下思路:
解析 <bean>
標籤,構建成 AbstractBeanDefinition (GenericBeanDefinition)
對象來存放全部解析出來的屬性。
將 AbstractBeanDefinition
、beanName
、aliasesArray
構建成 BeanDefinitionHolder
對象。
最後經過 BeanDefinitionHolder
將 beanName
和 BeanDefinition
註冊到 DefaultListableBeanFactory
中,也就是保存起來。
上文提到的兩個比較重要的屬性
beanDefinitionNames
和beanDefinitionMap
,在後面都會屢次用到,能夠重點關注一下。
最後,我模仿 Spring 寫了一個精簡版,代碼會持續更新。地址:https://github.com/leisurexi/tiny-spring。
《Spring 源碼深度解析》—— 郝佳