背景
上一篇我们介绍了容器的基本实现,结束时讲到这里进行 XML 的读取,本篇我们介绍默认标签(主要是 bean)的解析
parseBeanDefinitions(root, this.delegate);
/**
* 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) {if (delegate.isDefaultNamespace(root)) {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;
// 默认标签
if (delegate.isDefaultNamespace(ele)) {parseDefaultElement(ele, delegate);
}
else {
// 自定义标签
delegate.parseCustomElement(ele);
}
}
}
}
else {delegate.parseCustomElement(root);
}
}
1. 对各类型标签进行处理
parseDefaultElement(ele, delegate)
标签的详细解析是在 parseDefaultElement 中进行的,分别处理 import,alias,bean 和 beans 四种不同的标签
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {importBeanDefinitionResource(ele);
}
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {processAliasRegistration(ele);
}
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
2. 解析 Bean 标签
在 4 种标签解析中,对 bean 的标签解析最为复杂和重要,所以我们从此标签开始深入分析
1. 首先委托 BeanDefinitionDelegate 类的 parseBeanDefinitionElement 方法进行元素解析,返回 BeanDefinitionHolder 类型的实例 bdHolder,经过这个方法后,bdHoler 实例已经包含了我们配置文件中配置的各种属性了,例如 class,name,id,alias 之类的属性
delegate.parseBeanDefinitionElement(ele);
2. 当返回的 bdHolder 不为空的情况下若存在默认标签的子节点下再有自定义属性,还需要再次对自定义标签进行解析
delegate.decorateBeanDefinitionIfRequired(ele, bdHolder)
3. 解析完成后,需要对解析后的 bdHolder 进行注册,同样注册操作委托给了 BeanDefinitionReaderUtils 的 registerBeanDefinition 方法
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry());
4. 最后发出响应事件,通知相关监听器,这个 bean 已经加载完成了
this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
/**
* Process the given bean element, parsing the bean definition
* and registering it with the registry.
*/
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 解析 ele,返回 BeanDefinitionHolder 类型的实例 bdHolder,经过这个方法后 bdHolder 已经包含了配置文件中的各种属性了,例如 class、name、id、alias 等属性
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
// 如果返回的 bdHolder 不为空的情况下,如果存在默认标签下还有自定义属性,还需要再次对自定义属性标签进行解析
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
// 解析完成后,需要堆解析后的 bdHolder 进行注册,同样,注册操作委托给了 BeanDefinitionReaderUtils 的 registerBeanDefinition 方法
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 已经加载完成
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
2.1 解析 Element 元素
parseBeanDefinitionElement(Element ele)
这里主要涉及以下几步
1. 提取元素中的 id 以及 name 属性
2. 进一步解析其他所有属性并统一封装至 GenericBeanDefinition 类型的实例中
3. 如果检测到 bean 没有指定 beanName,那么使用默认规则为此 Bean 生成 beanName
4. 将获取到的信息封装到 BeanDefinitionHolder 的实例中
public static final String MULTI_VALUE_ATTRIBUTE_DELIMITERS = ",;";
@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {return parseBeanDefinitionElement(ele, null);
}
/**
* Parses the supplied {@code <bean>} element. May return {@code null}
* if there were errors during parse. Errors are reported to the
* {@link org.springframework.beans.factory.parsing.ProblemReporter}.
*/
@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
// 解析 id 属性
String id = ele.getAttribute(ID_ATTRIBUTE);
// 解析 name 属性
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
// 分割 name 属性 别名 将 nameAttr 按照 ,/; 分割,全部加入 aliases
List<String> aliases = new ArrayList<>();
if (StringUtils.hasLength(nameAttr)) {String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}
// 如果 id 和 name 都没有维护,就会报错
// 如果检测到 bean 没有指定 beanName,那么使用默认规则为此 Bean 生成 beanName
String beanName = id;
// 如果 beanName 为空且别名不为空,beanName 取别名数组的第 0 位, 此处将别名数组第 0 位移除
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {beanName = aliases.remove(0);
if (logger.isDebugEnabled()) {
logger.debug("No XML'id'specified - using'" + beanName +
"'as bean name and" + aliases + "as aliases");
}
}
// 检验名称唯一性
if (containingBean == null) {checkNameUniqueness(beanName, aliases, ele);
}
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {if (!StringUtils.hasText(beanName)) {
try {if (containingBean != null) {
beanName = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, this.readerContext.getRegistry(), true);
}
else {beanName = this.readerContext.generateBeanName(beanDefinition);
// Register an alias for the plain bean class name, if still possible,
// if the generator returned the class name plus a suffix.
// This is expected for Spring 1.2/2.0 backwards compatibility.
String beanClassName = beanDefinition.getBeanClassName();
if (beanClassName != null &&
beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {aliases.add(beanClassName);
}
}
if (logger.isDebugEnabled()) {
logger.debug("Neither XML'id'nor'name'specified -" +
"using generated bean name [" + beanName + "]");
}
}
catch (Exception ex) {error(ex.getMessage(), ele);
return null;
}
}
String[] aliasesArray = StringUtils.toStringArray(aliases);
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
return null;
}
2.1.1 检验名称唯一性
checkNameUniqueness(beanName, aliases, ele);
如果发现 benaName 已经使用过了,在这里报异常
/**
* Validate that the specified bean name and aliases have not been used already
* within the current level of beans element nesting.
*/
protected void checkNameUniqueness(String beanName, List<String> aliases, Element beanElement) {
// 发现的名称
String foundName = null;
// 如果已经使用过
if (StringUtils.hasText(beanName) && this.usedNames.contains(beanName)) {foundName = beanName;}
// 二次查询
if (foundName == null) {foundName = CollectionUtils.findFirstMatch(this.usedNames, aliases);
}
// 如果发现匹配内容
if (foundName != null) {error("Bean name'" + foundName + "'is already used in this <beans> element", beanElement);
}
// 通过校验 usedNames 增加 beanName 和 aliases, 再解析下一个 bean 的时候使用 usedNames 校验 beanName 是否重复
this.usedNames.add(beanName);
this.usedNames.addAll(aliases);
}
2.1.2 解析标签属性名称
parseBeanDefinitionElement(ele, beanName, containingBean);
/**
* Parse the bean definition itself, without regard to name or aliases. May return
* {@code null} if problems occurred during the parsing of the bean definition.
*/
@Nullable
public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean) {this.parseState.push(new BeanEntry(beanName));
// 解析 class 属性
String className = null;
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {className = ele.getAttribute(CLASS_ATTRIBUTE).trim();}
// 解析 parent 属性
String parent = null;
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());
// 解析构造函数参数
parseConstructorArgElements(ele, bd);
// 解析 property 子元素
parsePropertyElements(ele, bd);
// 解析 qualifier 子元素
parseQualifierElements(ele, bd);
bd.setResource(this.readerContext.getResource());
bd.setSource(extractSource(ele));
return bd;
}
catch (ClassNotFoundException ex) {error("Bean class [" + className + "] not found", ele, ex);
}
catch (NoClassDefFoundError err) {error("Class that bean class [" + className + "] depends on not found", ele, err);
}
catch (Throwable ex) {error("Unexpected failure during bean definition parsing", ele, ex);
}
finally {this.parseState.pop();
}
return null;
}
创建用于承载属性的 AbstractBeanDefinition 类型的 GenericBeanDefinition
createBeanDefinition(className, parent);
BeanDefinition 是一个接口,在 Spring 中存在三种实现:RootBeanDefinition,ChildBeanDefinition,GenericDefinition, 三种实现均继承 AbstractBeanDefinition,其中 BeanDefinition 是配置文件 <bean> 元素标签在容器中的内部表示形式。
Spring 通过 BeanDefinition 将配置文件中的 <bean> 配置信息转变为容器的内部表示,并注册到 BeanDefinitionRegistry 中
/**
* Create a bean definition for the given class name and parent name. 创建一个针对给定类和父类的 bean 定义
* @param className the name of the bean class
* @param parentName the name of the bean's parent bean
* @return the newly created bean definition
* @throws ClassNotFoundException if bean class resolution was attempted but failed
*/
protected AbstractBeanDefinition createBeanDefinition(@Nullable String className, @Nullable String parentName)
throws ClassNotFoundException {
return BeanDefinitionReaderUtils.createBeanDefinition(parentName, className, this.readerContext.getBeanClassLoader());
}
/**
* Create a new GenericBeanDefinition for the given parent name and class name,
* eagerly loading the bean class if a ClassLoader has been specified.
* @param parentName the name of the parent bean, if any
* @param className the name of the bean class, if any
* @param classLoader the ClassLoader to use for loading bean classes
* (can be {@code null} to just register bean classes by name)
* @return the bean definition
* @throws ClassNotFoundException if the bean class could not be loaded
*/
public static AbstractBeanDefinition createBeanDefinition(@Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException {GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setParentName(parentName);
//parentName 可能为空
if (className != null) {
// 如果 classLoader 不为空,则使用已传入的 classLoader 同一虚拟机加载类对象,否则只是记录 className
if (classLoader != null) {bd.setBeanClass(ClassUtils.forName(className, classLoader));
}
else {bd.setBeanClassName(className);
}
}
return bd;
}
2.1.2.1 解析 bean 各种属性
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
Spring 在 parseBeanDefinitionAttributes 中完成了对 bean 属性的解析,基本上常用的和不常用的都在这里了
/**
* Apply the attributes of the given bean element to the given bean * definition. 将给定 bean 元素的属性应用于给定 bean 定义
* @param ele bean declaration element
* @param beanName bean name
* @param containingBean containing bean definition
* @return a bean definition initialized according to the bean element attributes
*/
public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
@Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) {
// 解析 singleton 属性
if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {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));
}
else if (containingBean != null) {
// Take default from containing bean in case of an inner bean definition.
bd.setScope(containingBean.getScope());
}
// 解析 abstract 属性
if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
}
// 解析 lazy-init 属性
String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
if (DEFAULT_VALUE.equals(lazyInit)) {lazyInit = this.defaults.getLazyInit();
}
// 没有设置或者设置成其他字符,都是 false
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 属性
String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE);
if ("".equals(autowireCandidate) || DEFAULT_VALUE.equals(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);
}
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);
}
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;
}
2.1.2.2 解析子元素 meta
parseMetaElements(ele, bd);
子元素只是一个额外的声明,需要使用的时候可以通过 BeanDefinition 的 getAttribute(key)方法进行获取
public void parseMetaElements(Element ele, BeanMetadataAttributeAccessor attributeAccessor) {NodeList nl = ele.getChildNodes();
// 获取当前节点的所有子元素
for (int i = 0; i < nl.getLength(); i++) {Node node = nl.item(i);
// 提取 mata
if (isCandidateElement(node) && nodeNameEquals(node, META_ELEMENT)) {Element metaElement = (Element) node;
String key = metaElement.getAttribute(KEY_ATTRIBUTE);
String value = metaElement.getAttribute(VALUE_ATTRIBUTE);
// 使用 key 和 value 构造 BeanMetadataAttribute
BeanMetadataAttribute attribute = new BeanMetadataAttribute(key, value);
attribute.setSource(extractSource(metaElement));
// 记录信息
attributeAccessor.addMetadataAttribute(attribute);
}
}
}
2.1.2.3 解析子元素 lookup-method
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
lookup-method 可以用来实现一些热插拔的功能,动态实现一些方法
/**
* Parse lookup-override sub-elements of the given bean element.
*/
public void parseLookupOverrideSubElements(Element beanEle, MethodOverrides overrides) {NodeList nl = beanEle.getChildNodes();
// 获取当前节点所有子元素
for (int i = 0; i < nl.getLength(); i++) {Node node = nl.item(i);
// 仅当在 Spring 默认子元素下且为 <lookup-method 时有效
if (isCandidateElement(node) && nodeNameEquals(node, LOOKUP_METHOD_ELEMENT)) {Element ele = (Element) node;
// 获取要修饰的方法
String methodName = ele.getAttribute(NAME_ATTRIBUTE);
// 获取配置返回的 bean
String beanRef = ele.getAttribute(BEAN_ELEMENT);
LookupOverride override = new LookupOverride(methodName, beanRef);
override.setSource(extractSource(ele));
// 添加 override
overrides.addOverride(override);
}
}
}
2.1.2.4 解析子元素 replaced-method
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
replaced-method 可以动态替换原有的方法
/**
* Parse replaced-method sub-elements of the given bean element.
*/
public void parseReplacedMethodSubElements(Element beanEle, MethodOverrides overrides) {NodeList nl = beanEle.getChildNodes();
// 获取当前节点所有子元素
for (int i = 0; i < nl.getLength(); i++) {Node node = nl.item(i);
// 仅当在 Spring 默认子元素下且为 <replaced-method 时有效
if (isCandidateElement(node) && nodeNameEquals(node, REPLACED_METHOD_ELEMENT)) {Element replacedMethodEle = (Element) node;
// 提取要替换的旧的方法
String name = replacedMethodEle.getAttribute(NAME_ATTRIBUTE);
// 提取对应的新的替换方法
String callback = replacedMethodEle.getAttribute(REPLACER_ATTRIBUTE);
ReplaceOverride replaceOverride = new ReplaceOverride(name, callback);
// Look for arg-type match elements.
List<Element> argTypeEles = DomUtils.getChildElementsByTagName(replacedMethodEle, ARG_TYPE_ELEMENT);
for (Element argTypeEle : argTypeEles) {
// 获取参数
String match = argTypeEle.getAttribute(ARG_TYPE_MATCH_ATTRIBUTE);
match = (StringUtils.hasText(match) ? match : DomUtils.getTextValue(argTypeEle));
if (StringUtils.hasText(match)) {replaceOverride.addTypeIdentifier(match);
}
}
replaceOverride.setSource(extractSource(replacedMethodEle));
// 添加 replaceOverride
overrides.addOverride(replaceOverride);
}
}
}
2.1.2.5 解析构造参数函数
parseConstructorArgElements(ele, bd);
处理配置构造函数的情况
<constructor-arg name="id" value="1"/>
<constructor-arg name="name" value="student"/>
<constructor-arg name="dream">
<list>
<value>soldier</value>
<value>scientist</value>
<value>pilot</value>
</list>
</constructor-arg>
首先提取 constructor-arg 上必要的属性(index,type,name)
如果指定了 index 属性,操作如下
1. 解析 Constructor-args 的子元素
2. 使用 ConstructorArgumentValues.ValueHolder 类型来封装解析出来的元素
3. 将 type、name、index 属性一并封装在 ConstructorArgmentValues.ValueHolder 类型中并添加至当前 BeanDefinition 的 constructorArgumentValues 的 indexedArgumentValues 属性中
如果没有指定 index 属性,操作步骤如下
1. 解析 constructor-args 的子元素
2. 使用 ConstructorArgumentValues.ValudHolder 类型来封装解析出来的元素
3. 将 type、name、index 属性一并封装在 ConstructorArgmentValues.ValueHolder 类型中并添加至当前 BeanDefinition 的 constructorArgumentValues 的 genericArgumentValues 属性中
/**
* Parse constructor-arg sub-elements of the given bean element.
*/
public void parseConstructorArgElements(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, CONSTRUCTOR_ARG_ELEMENT)) {
// 解析构造函数参数
parseConstructorArgElement((Element) node, bd);
}
}
}
/**
* Parse a constructor-arg element.
*/
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);
if (StringUtils.hasLength(indexAttr)) {
// 如果有 index 属性
try {int index = Integer.parseInt(indexAttr);
if (index < 0) {error("'index' cannot be lower than 0", ele);
}
else {
try {this.parseState.push(new ConstructorArgumentEntry(index));
// 解析 ele 对应的属性元素
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));
// 不允许重复指定相同参数
if (bd.getConstructorArgumentValues().hasIndexedArgumentValue(index)) {error("Ambiguous constructor-arg entries for index" + index, ele);
}
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 {
// 没写 index 属性,自动寻找
try {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));
bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder);
}
finally {this.parseState.pop();
}
}
}
解析 ele 对应的属性元素
Object value = parsePropertyValue(ele, bd, null);
构造函数中配置子元素的过程
解析过程
1. 略过 descripion 或者 meta
2. 提取 constructor-arg 上的 ref 和 value 属性,以便于根据规则验证正确性,其规则为 constructor-arg 上不存在以下情况
同时既有 ref 属性又有 value 属性
存在 ref 属性或者 value 属性且又有子元素
3.ref 属性的处理,使用 RuntimeBeanReference 封装对应的 rfc 名称,如
<constructor-arg ref="a">
4.value 属性值的处理。使用 TypedStringValue 封装,如
<constructor-arg value="a">
5. 子元素的处理,如
<constructor-arg>
<map>
<entry key="key" value="value"/>
</map>
</constructor-arg>
/**
* Get the value of a property element. May be a list etc.
* Also used for constructor arguments, "propertyName" being null in this case.
*/
@Nullable
public Object parsePropertyValue(Element ele, BeanDefinition bd, @Nullable String propertyName) {String elementName = (propertyName != null) ?
"<property> element for property'" + propertyName + "'":"<constructor-arg> element";
// Should only have one child element: ref, value, list, etc.
// 一个属性只能对应一种类型:ref、value、list 等
// 获取所有子节点
NodeList nl = ele.getChildNodes();
Element subElement = null;
for (int i = 0; i < nl.getLength(); i++) {Node node = nl.item(i);
// 不处理 descroption 和 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;
}
}
}
// 解析 constructor-arg 上的 ref 属性
boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
// 解析 constructor-arg 上的 value 属性
boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
if ((hasRefAttribute && hasValueAttribute) ||
((hasRefAttribute || hasValueAttribute) && subElement != null)) {
//ref 和 value 都不为空报错,存在 ref 或者 value 属性且存在子元素报错
error(elementName +
"is only allowed to contain either'ref'attribute OR'value'attribute OR sub-element", ele);
}
// 如果存在 ref 属性
if (hasRefAttribute) {
// 使用 RuntimeBeanReference 封装对应的 ref 名称
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;
}
else if (hasValueAttribute) {
// 如果存在 value 属性, 使用 TypedStringValue 封装
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 报错
// Neither child element nor "ref" or "value" attribute found.
error(elementName + "must specify a ref or value", ele);
return null;
}
}
2.1.2.6 解析子元素 Property
parsePropertySubElement(subElement, bd);
@Nullable
public Object parsePropertySubElement(Element ele, @Nullable BeanDefinition bd) {return parsePropertySubElement(ele, bd, null);
}
/**
* Parse a value, ref or collection sub-element of a property or
* constructor-arg element.
* @param ele subelement of property element; we don't know which yet
* @param defaultValueType the default type (class name) for any
* {@code <value>} tag that might be created
*/
@Nullable
public Object parsePropertySubElement(Element ele, @Nullable BeanDefinition bd, @Nullable String defaultValueType) {
// 如果不是默认标签,走自定义标签解析
if (!isDefaultNamespace(ele)) {return parseNestedCustomElement(ele, bd);
}
else if (nodeNameEquals(ele, BEAN_ELEMENT)) {// 如果是 bean, 解析标签属性名称
BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd);
if (nestedBd != null) {
// 如果返回的 bdHolder 不为空的情况下,如果存在默认标签下还有自定义属性,还需要再次对自定义属性标签进行解析
nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd);
}
return nestedBd;
}
else if (nodeNameEquals(ele, REF_ELEMENT)) {//ref 属性
// A generic reference to any name of any bean.
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.
// 解析 parent
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)) {
// It's a distinguished null value. Let's wrap it in a TypedStringValue
// object in order to preserve the source location.
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;
}
}
解析子元素 property
parsePropertyElements(ele, bd);
parsePropertyElements 函数完成了对 property 属性的提取,property 使用方法如下:
<bean id=”test” class=”test.TestClass”>
<property name="testStr" value="aaa">
</bean>
或者
<bean id=”a”>
<property name="p">
<list>
<value>aa</value>
<value>bb</value>
<list>
<property>
</bean>
具体的解析过程
提取所有 property 属性子元素,调用 parsePropertyElement 处理
将返回值使用 PropertyValue 进行封装,并记录在 BeanDefinition 中的 propertyValues 中
/**
* Parse property sub-elements of the given bean element.
*/
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)) {parsePropertyElement((Element) node, bd);
}
}
}
/**
* Parse a property element.
*/
public void parsePropertyElement(Element ele, BeanDefinition bd) {
// 获取元素中 name 的值
String propertyName = ele.getAttribute(NAME_ATTRIBUTE);
if (!StringUtils.hasLength(propertyName)) {error("Tag'property'must have a'name'attribute", ele);
return;
}
this.parseState.push(new PropertyEntry(propertyName));
try {
// 不允许多次对同一属性配置
if (bd.getPropertyValues().contains(propertyName)) {error("Multiple'property'definitions for property'" + propertyName + "'", ele);
return;
}
Object val = parsePropertyValue(ele, bd, propertyName);
PropertyValue pv = new PropertyValue(propertyName, val);
parseMetaElements(ele, pv);
pv.setSource(extractSource(ele));
bd.getPropertyValues().addPropertyValue(pv);
}
finally {this.parseState.pop();
}
}
2.1.2.7 解析子元素 qualifier
parseQualifierElements(ele, bd);
/**
* Parse qualifier sub-elements of the given bean element.
*/
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)) {parseQualifierElement((Element) node, bd);
}
}
}
/**
* Parse lookup-override sub-elements of the given bean element.
*/
public void parseLookupOverrideSubElements(Element beanEle, MethodOverrides overrides) {NodeList nl = beanEle.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {Node node = nl.item(i);
if (isCandidateElement(node) && nodeNameEquals(node, LOOKUP_METHOD_ELEMENT)) {Element ele = (Element) node;
String methodName = ele.getAttribute(NAME_ATTRIBUTE);
String beanRef = ele.getAttribute(BEAN_ELEMENT);
LookupOverride override = new LookupOverride(methodName, beanRef);
override.setSource(extractSource(ele));
overrides.addOverride(override);
}
}
}
至此完成了 XML 文档到 GenericBeanDefinition 的转换,也就是说这时 XML 所有默认标签配置都可以在 GenericBeanDefinition 中找到
3. 解析默认标签内部的其定义标签
返回 org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader 的标签解析起始函数 protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate)
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
在 decorateBeanDefinitionIfRequired 中我们可以看到对于程序默认的标签的处理过程其实是略过的,因为默认标签已经被处理完了,这里只对自定义的标签或者说对 bean 的自定义属性感兴趣
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder definitionHolder) {return decorateBeanDefinitionIfRequired(ele, definitionHolder, null);
}
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder definitionHolder, @Nullable BeanDefinition containingBd) {
BeanDefinitionHolder finalDefinition = definitionHolder;
// 遍历所有属性,看看是否存在适用于修饰的属性
// Decorate based on custom attributes first.
NamedNodeMap attributes = ele.getAttributes();
for (int i = 0; i < attributes.getLength(); i++) {Node node = attributes.item(i);
finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
}
// 遍历所有子节点,看看是否存在适用于修饰的属性
// Decorate based on custom nested elements.
NodeList children = ele.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {Node node = children.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
}
}
return finalDefinition;
}
decorateIfRequired(node, finalDefinition, containingBd)
public BeanDefinitionHolder decorateIfRequired(Node node, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {
// 获取自定义标签的命名空间
String namespaceUri = getNamespaceURI(node);
// 对非默认标签进行修饰
if (namespaceUri != null && !isDefaultNamespace(namespaceUri)) {
// 根据命名空间找到对应的处理器
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler != null) {
// 进行修饰
BeanDefinitionHolder decorated =
handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd));
if (decorated != null) {return decorated;}
}
else if (namespaceUri.startsWith("http://www.springframework.org/")) {error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", node);
}
else {
// A custom namespace, not to be handled by Spring - maybe "xml:...".
if (logger.isDebugEnabled()) {logger.debug("No Spring NamespaceHandler found for XML schema namespace [" + namespaceUri + "]");
}
}
}
return originalDef;
}
4. 注册解析 BeanDefinition
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
对于配置文件,解析完成,装饰也完成了,得到的 beanDefinition 已经满足后续需求了,剩下的就是注册了,解析的 beanDefinition 会被注册到 BeanDefinitionRegistry 类型的实例 registry 中,其中有两部分,通过 beanName 注册和通过别名注册
/**
* Register the given bean definition with the given bean factory.
* @param definitionHolder the bean definition including name and aliases
* @param registry the bean factory to register with
* @throws BeanDefinitionStoreException if registration failed
*/
public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// Register bean definition under primary name.
// 使用 beanName 作为注册唯一标识
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// Register aliases for bean name, if any.
// 注册所有别名
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {for (String alias : aliases) {registry.registerAlias(beanName, alias);
}
}
}
4.1 通过 beanName 注册
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
在对应 bean 的注册处理方式上,主要进行了几个步骤
1. 对于 AbstractBeanDefinition 的校验,在解析 XML 文件的时候我们提到过校验,但此校验非彼校验,之前的校验是针对 XML 文件格式的校验,而此时的校验是对于 AbstractBeanDefinition 的 methodOverrides 属性的
2. 对于 beanName 已经注册的情况的处理,如果设置了不允许 bean 的覆盖,则抛出异常,否则直接覆盖
3. 加入 map 缓存
4. 清除之前留下的对于的 beanName 的缓存
/** List of bean definition names, in registration order */
private volatile List<String> beanDefinitionNames = new ArrayList<>(256);
// 单例模式 beanName 列表
/** List of names of manually registered singletons, in registration order */
private volatile Set<String> manualSingletonNames = new LinkedHashSet<>(16);
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
// 验证 BeanName
Assert.hasText(beanName, "Bean name must not be empty");
// 验证 Bean 定义
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
// 注册前最后一次校验,这里的校验不同于之前的 XML 文件校验,// 主要是对于 AbstractBeanDefinition 属性中的 methodOverrides 校验
// 校验 methodOverrides 是否与工厂方法并存或者 methodOverrides 对应的方法不存在
if (beanDefinition instanceof AbstractBeanDefinition) {
try {((AbstractBeanDefinition) beanDefinition).validate();}
catch (BeanDefinitionValidationException ex) {throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
BeanDefinition oldBeanDefinition;
oldBeanDefinition = this.beanDefinitionMap.get(beanName);
// 处理已经注册过的 beanName 情况
if (oldBeanDefinition != null) {
// 如果对应的 beanName 已经注册并且在配置中配置了 bean 不允许被覆盖,则抛出异常
if (!isAllowBeanDefinitionOverriding()) {throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean'" + beanName +
"': There is already [" + oldBeanDefinition + "] bound.");
}
else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (this.logger.isWarnEnabled()) {
this.logger.warn("Overriding user-defined bean definition for bean'" + beanName +
"'with a framework-generated bean definition: replacing [" +
oldBeanDefinition + "] with [" + beanDefinition + "]");
}
}
else if (!beanDefinition.equals(oldBeanDefinition)) {if (this.logger.isInfoEnabled()) {
this.logger.info("Overriding bean definition for bean'" + beanName +
"'with a different definition: replacing [" + oldBeanDefinition +
"] with [" + beanDefinition + "]");
}
}
else {if (this.logger.isDebugEnabled()) {
this.logger.debug("Overriding bean definition for bean'" + beanName +
"'with an equivalent definition: replacing [" + oldBeanDefinition +
"] with [" + beanDefinition + "]");
}
}
// 注册 beanDefinition
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
//hasBeanCreationStarted 检查该工厂的 bean 创建阶段是否已经开始
if (hasBeanCreationStarted()) {// 已经开始
// Cannot modify startup-time collection elements anymore (for stable iteration)
// beanDefinitionMap 是全局变量,这里存在并发访问的情况
synchronized (this.beanDefinitionMap) {
// 注册 beanDefinition
this.beanDefinitionMap.put(beanName, beanDefinition);
// 新建已更新的 beanDefinition 列表,大小为已注册 beanDefinitionName 列表大小 + 1
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
// 加入所有已注册的 beanDefinitionName
updatedDefinitions.addAll(this.beanDefinitionNames);
// 加入本次注册的 beanName
updatedDefinitions.add(beanName);
// 更新已注册的 beanDefinitionName 列表为 updatedDefinitions, 为什么不直接更新?ArrayList 可以动态扩展, 但是在插入新的数据并不是申请一个空间,时是直接将现有长度乘以 2 然后把元素复制过去,所以设置一个合适的长度可以减少空间的浪费
this.beanDefinitionNames = updatedDefinitions;
// 如果单例模式 beanName 列表包含本次注册的 beanName
if (this.manualSingletonNames.contains(beanName)) {Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
// 就将其移除掉
updatedSingletons.remove(beanName);
this.manualSingletonNames = updatedSingletons;
}
}
}
// 该工厂的 bean 创建阶段没有开始
else {
// Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;
}
// 重置 beanName 对应的缓存
if (oldBeanDefinition != null || containsSingleton(beanName)) {resetBeanDefinition(beanName);
}
}
/**
* 重置所有 beanName 对应的缓存
* Reset all bean definition caches for the given bean,
* including the caches of beans that are derived from it.
* @param beanName the name of the bean to reset
*/
protected void resetBeanDefinition(String beanName) {
// Remove the merged bean definition for the given bean, if already created.
clearMergedBeanDefinition(beanName);
// Remove corresponding bean from singleton cache, if any. Shouldn't usually
// be necessary, rather just meant for overriding a context's default beans
// (e.g. the default StaticMessageSource in a StaticApplicationContext).
destroySingleton(beanName);
// Reset all bean definitions that have the given bean as parent (recursively).
// 重设所有以 beanName 为父 bean 的 bean 的缓存
for (String bdName : this.beanDefinitionNames) {if (!beanName.equals(bdName)) {BeanDefinition bd = this.beanDefinitionMap.get(bdName);
if (beanName.equals(bd.getParentName())) {resetBeanDefinition(bdName);
}
}
}
}
4.2 通过别名注册
registry.registerAlias(beanName, alias);
alias 和 beanName 相同的情况下,如果 alias 和 beanName 名称相同就不需要处理,并移除原有 alias
alias 覆盖处理,若 aliasName 已经使用并且指向另一个 beanName 则需要用户的设置进行处理
alias 循环检查,当 A ->B 存在时,如果 A ->C->B 出现就抛出异常
注册 alias
@Override
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 和 alias 相同的话不记录 alias, 并删除对应的 alias
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;
}
// 如果 alias 不允许被覆盖
if (!allowAliasOverriding()) {
throw new IllegalStateException("Cannot register alias'" + alias + "'for name'" +
name + "': It is already registered for name'" + registeredName + "'.");
}
}
// 校验是否存在循环例如:A->B 存在时,不能出现 A->C->B
checkForAliasCircle(name, alias);
// 注册 alias
this.aliasMap.put(alias, name);
}
}
}
5. 通知监听器解析以及注册完成
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
//Spring 中并没有对此做逻辑处理,开发人员需要时可以通过注册监听器的方式将处理逻辑写进监听器中
protected final XmlReaderContext getReaderContext() {Assert.state(this.readerContext != null, "No XmlReaderContext available");
return this.readerContext;
}
至此标签解析完成