本系列所有基于 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 源码深度解析》—— 郝佳