Spring IoC 默认标签解析
前言
本系列全部基于 Spring 5.2.2.BUILD-SNAPSHOT
版本。因为 Spring 整个体系太过于庞大,所以只会进行关键部分的源码解析。
本篇文章主要介绍 Spring IoC 容器怎么解析默认标签的。
正文
所谓的默认标签就是 import
、alias
、bean
、beans
这四个标签。
DefaultBeanDefinitionDocumentReader#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)) {
doRegisterBeanDefinitions(ele);
}
}
上面 parseDefaultElement
方法中对 bean 标签的处理方法 processBeanDefinition
最为重要,下面来着重分析一下。
DefaultBeanDefinitionDocumentReader#processBeanDefinition
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));
}
}
BeanDefinitionParseDelegate#parseBeanDefinitionElement
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
生成一个默认的名称,主要规则如下:
- 获取
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;
// 省略其它代码...
}
BeanDefinitionParserDelegate#parseBeanDefinitionAttributes
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
中定义的属性就一目了然了,这里限于篇幅原因就不展示了。
BeanDefinitionParserDelegate#parseConstructorArgElements
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
中。
- 解析
BeanDefinitionParserDelegate#parsePropertyValue
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;
}
}
从上面的代码来看,对构造函数中属性元素的解析,步骤如下:
- 略过
description
或者meta
。 - 提取
constructor-arg
上的ref
和value
属性,以便于根据规则验证正确性。其规则为在constructor-arg
上不存在以下情况:- 同时存在
ref
和value
属性。 - 存在
ref
或者value
属性,并且又有子元素。
- 同时存在
BeanDefinitionParserDelegate#parsePropertyElements
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
方法否则在赋值阶段会抛出异常。
BeanDefinitionParserDelegate#parseQualifierElements
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
的名称,这样歧义就消除了。
BeanDefinitionReaderUtils#registerBeanDefinition
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 源码深度解析》—— 郝佳