写在前面
本篇在这篇文章基础上继续分析。本篇主要分析的是bean标签的解析过程。
1:作用
没得说,配置spring bean。
2:测试代码
为了方便调试再贴下测试代码:
@Test
public void testBeanDefinitionLoad() {
// 定义资源
ClassPathResource classPathResource = new ClassPathResource("testbeandefinition.xml");
// 定义IOC容器
DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
// 定义bean定义读取器
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(defaultListableBeanFactory);
// 通过bean定义读取器从资源中读取bean定义
int i = xmlBeanDefinitionReader.loadBeanDefinitions(classPathResource);
System.out.println("bean定义的个数是:" + i);
}
xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="testBeanDefinitionBean" class="yudaosourcecode.spring.TestBeanDefinitionBean"/>
<bean id="testBeanDefinitionBean1" class="yudaosourcecode.spring.TestBeanDefinitionBean"/>
</beans>
然后在org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#parseDefaultElement
处打如下断点,就可以开始调试了:
3:processBeanDefinition
源码:
org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#processBeanDefinition
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// <2021-03-01 13:36>
// 获取持有name和alias的DeanDefinitionHolder实例对象
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
// 获取到了
if (bdHolder != null) {
// 进行自定义标签处理,如id,name,class,lazy-init等,不是很影响主流程,先不深究
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);
}
// 触发事件
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
<2021-03-01 13:36>
处代码参看3.1:parseBeanDefinitionElement
3.1:parseBeanDefinitionElement
源码:
org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseBeanDefinitionElement(org.w3c.dom.Element)
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
return parseBeanDefinitionElement(ele, null);
}
继续:
org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseBeanDefinitionElement(org.w3c.dom.Element, org.springframework.beans.factory.config.BeanDefinition)
@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
// 获取id属性
String id = ele.getAttribute(ID_ATTRIBUTE);
// 获取name属性
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
// <2021-03-02 17:47>
List<String> aliases = new ArrayList<>();
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}
// 默认将id作为bean名称,即id属性的优先级高于name属性
String beanName = id;
// 如果是没有设置id,并且设置了name属性,则取第一个作为beanName
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
// 取出并删除第一个作为beanName
beanName = aliases.remove(0);
if (logger.isTraceEnabled()) {
logger.trace("No XML 'id' specified - using '" + beanName +
"' as bean name and " + aliases + " as aliases");
}
}
// <2021-03-02 17:52>
if (containingBean == null) {
checkNameUniqueness(beanName, aliases, ele);
}
// <2021-03-02 17:53>
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
// 成功解析出beandefinition
if (beanDefinition != null) {
// 本部分是在id和name都没有值的时候,使用默认规则生成bean名称,非重点,可以忽略
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);
}
}
if (logger.isTraceEnabled()) {
logger.trace("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);
// 使用beandefinition,bean名称,别名数组作为参数构造BeanDefinitionHolder
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
return null;
}
<2021-03-02 17:47>
处是使用配置的name属性作为别名,如下配置:
<bean id="testBeanDefinitionBean" class="yudaosourcecode.spring.TestBeanDefinitionBean"
name="name_1,name_2,name_3"/>
debug结果如下图:
<2021-03-02 17:52>
参考3.2:checkNameUniqueness
,<2021-03-02 17:53>
参看3.3:parseBeanDefinitionElement(ele, beanName, containingBean)
3.2:checkNameUniqueness
源码:
org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#checkNameUniqueness
protected void checkNameUniqueness(String beanName, List<String> aliases, Element beanElement) {
// 已经存在的bean名称
String foundName = null;
// 如果是传入的bean名称不为空,并且已使用名称包含,则赋值当前
// bean名称为已存在bean名称
if (StringUtils.hasText(beanName) && this.usedNames.contains(beanName)) {
foundName = beanName;
}
// 如果是从传入的bean名称没有发现,则尝试从别名数组中查找
if (foundName == null) {
foundName = CollectionUtils.findFirstMatch(this.usedNames, aliases);
}
// 如果是存在,则抛出错误
if (foundName != null) {
error("Bean name '" + foundName + "' is already used in this <beans> element", beanElement);
}
// 添加传入bean名称到已使用的set集合中
this.usedNames.add(beanName);
// 添加所有别名到已使用的set集合中
this.usedNames.addAll(aliases);
}
3.3:parseBeanDefinitionElement(ele, beanName, containingBean)
源码:
org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseBeanDefinitionElement(org.w3c.dom.Element, java.lang.String, org.springframework.beans.factory.config.BeanDefinition)
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();
}
// <2021-03-02 19:01>
// 设置parent属性
String parent = null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
try {
// <2021-03-02 19:08>
// 创建用于承载配置信息的beandefinition
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
// 解析各种属性
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
// 设置描述
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
/*** 解析bean标签的内部子元素开始 ***/
// <2021-03-03 14:42>
// 解析元数据 <meta />
parseMetaElements(ele, bd);
// <2021-03-03 14:43>
// 解析lookup-method
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
// <2021-03-03 14:44>
// 解析replaced-method
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
// <2021-03-04 18:39>
// 解析constructor-arg
parseConstructorArgElements(ele, bd);
// <2021-03-04 18:42>
// 解析property
parsePropertyElements(ele, bd);
// <2021-03-04 18:43>
// 解析qualifier
parseQualifierElements(ele, bd);
/*** 解析bean标签的内部子元素结束 ***/
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;
}
<2021-03-02 19:01>
设置parent属性,关于parent属性可以参考这里。<2021-03-02 19:08>
参考3.4:createBeanDefinition
。<2021-03-03 14:42>
处参考4.1:meta子标签解析
,<2021-03-03 14:43>
处参考4.2:lookup-method子标签解析
,<2021-03-03 14:44>
处参考代码replaced-method子标签解析
,<2021-03-04 18:39>
处参考4.4:constructor-arg子标签解析
,<2021-03-04 18:42>
处参考4.5:property子标签解析
,<2021-03-04 18:43>
处参考4.6:qualifier子标签解析
。
3.4:createBeanDefinition
BeanDefinition的顶层接口是org.springframework.beans.factory.config.BeanDefinition
,该方法返回的是其实现类org.springframework.beans.factory.support.GenericBeanDefinition
,看源码:
org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#createBeanDefinition
protected AbstractBeanDefinition createBeanDefinition(@Nullable String className, @Nullable String parentName)
throws ClassNotFoundException {
return BeanDefinitionReaderUtils.createBeanDefinition(
parentName, className, this.readerContext.getBeanClassLoader());
}
继续:
org.springframework.beans.factory.support.BeanDefinitionReaderUtils#createBeanDefinition
public static AbstractBeanDefinition createBeanDefinition(
@Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException {
GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setParentName(parentName);
if (className != null) {
if (classLoader != null) {
bd.setBeanClass(ClassUtils.forName(className, classLoader));
}
else {
bd.setBeanClassName(className);
}
}
return bd;
}
直接使用工具类创建了GenericBeanDefinition
的实例。
4:bean子标签解析
4.1:meta子标签解析
meta标签只是一种信息补充的方式,不会体现在最终生成的bean对象中。
源码:
org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseMetaElements
public void parseMetaElements(Element ele, BeanMetadataAttributeAccessor attributeAccessor) {
// 获取当前bean标签的所有子标签,当然后续只处理其中的<meta>子标签
NodeList nl = ele.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
// 这里isCandidateElement判断必须是默认命名空间下的元素,即
// http://www.springframework.org/schema/beans命名空间
// nodeNameEquals(node, META_ELEMENT)判断必须是meta标签
// 也正是本方法要解析的标签
// 如:<meta key="key1" value="value1"/>
if (isCandidateElement(node) && nodeNameEquals(node, META_ELEMENT)) {
// 强转
Element metaElement = (Element) node;
// 获取key
String key = metaElement.getAttribute(KEY_ATTRIBUTE);
// 获取value
String value = metaElement.getAttribute(VALUE_ATTRIBUTE);
// 将key+value封装为BeanMetadataAttribute
BeanMetadataAttribute attribute = new BeanMetadataAttribute(key, value);
// extractSource(metaElement)调用的最终是直接return null的,所以可以暂时忽略
attribute.setSource(extractSource(metaElement));
// <2021-03-03 15:32>
attributeAccessor.addMetadataAttribute(attribute);
}
}
}
<2021-03-03 15:32>
处attributeAccessor的入参的类型为AbstractBeanDefinition
,但是其是继承了BeanMetadataAttributeAccessor
,如下:
public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
implements BeanDefinition, Cloneable {}
因此具有BeanMetadataAttributeAccessor
的能力,addMetadataAttribute
源码如下:
org.springframework.beans.BeanMetadataAttributeAccessor#addMetadataAttribute
public void addMetadataAttribute(BeanMetadataAttribute attribute) {
super.setAttribute(attribute.getName(), attribute);
}
继续:
org.springframework.core.AttributeAccessorSupport#setAttribute
@Override
public void setAttribute(String name, @Nullable Object value) {
Assert.notNull(name, "Name must not be null");
if (value != null) {
// private final Map<String, Object> attributes = new LinkedHashMap<>();
this.attributes.put(name, value);
}
else {
removeAttribute(name);
}
}
最终将信息存储到org.springframework.core.AttributeAccessorSupport
的map集合中。
4.2:lookup-method子标签解析
关于lookup-method
的用法可以参考这里。
源码:
org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseLookupOverrideSubElements
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;
// name属性就是调用获取bean的方法的名称
String methodName = ele.getAttribute(NAME_ATTRIBUTE);
// bean属性就是要返回的bean的bean名称
String beanRef = ele.getAttribute(BEAN_ELEMENT);
// 通过方法名称和bean名称构造LookupMethod对象
LookupOverride override = new LookupOverride(methodName, beanRef);
override.setSource(extractSource(ele));
// <2021-03-03 16:59>
overrides.addOverride(override);
}
}
}
<2021-03-03 16:59>
是添加lookup-method信息即override到overrides中,overrides是一个存储LookupOverride的容器对象,源码如下:
org.springframework.beans.factory.support.MethodOverrides
public class MethodOverrides {
private final Set<MethodOverride> overrides = new CopyOnWriteArraySet<>();
}
4.3:replaced-method子标签解析
具体用法可以参看这里。
源码:
org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseReplacedMethodSubElements
public void parseReplacedMethodSubElements(Element beanEle, MethodOverrides overrides) {
// 获取bean标签的所有元素
NodeList nl = beanEle.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
/// 默认命名空间下的replaced-method标签才处理
if (isCandidateElement(node) && nodeNameEquals(node, REPLACED_METHOD_ELEMENT)) {
// 强转
Element replacedMethodEle = (Element) node;
// 获取要替换的方法名称
String name = replacedMethodEle.getAttribute(NAME_ATTRIBUTE);
// 执行具体替换操作的bean名称
String callback = replacedMethodEle.getAttribute(REPLACER_ATTRIBUTE);
// 构造ReplaceOverride对象
ReplaceOverride replaceOverride = new ReplaceOverride(name, callback);
// 获取子元素arg-type,目前不清楚怎么用,用到了再看
List<Element> argTypeEles = DomUtils.getChildElementsByTagName(replacedMethodEle, ARG_TYPE_ELEMENT);
// 循环处理arg-type子标签,处理其中的match属性
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));
overrides.addOverride(replaceOverride);
}
}
}
4.4:constructor-arg子标签解析
这种方式相当于是指派构造函数让spring调用创建对象。
测试使用的xml配置文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="bookService" class="yudaosourcecode.constructorarg.BookService"/>
<bean id="studentService" class="yudaosourcecode.constructorarg.StudentService">
<constructor-arg index="0" value="chenssy"/>
<constructor-arg name="age" value="100"/>
<constructor-arg name="bookService" ref="bookService"/>
</bean>
</beans>
源码:
org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseConstructorArgElements
public void parseConstructorArgElements(Element beanEle, BeanDefinition bd) {
NodeList nl = beanEle.getChildNodes();
// 遍历所有的标签,如果是默认命名空间下的constructor-arg
// 则调用parseConstructorArgElement方法处理
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);
}
}
}
我们接着来看parseConstructorArgElement
方法源码:
org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseConstructorArgElement
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)) {
try {
int index = Integer.parseInt(indexAttr);
// 判断不小于0
if (index < 0) {
error("'index' cannot be lower than 0", ele);
}
else {
try {
// 存储索引信息到parseState中,其中ConstructorArgumentEntry
// 代表的是构造函数的参数信息,如参数位置,参数名称,参数类型等
this.parseState.push(new ConstructorArgumentEntry(index));
// <2021-03-05 11:19>
// 解析contructor-arg中的属性,如ref,value等
// 其实就是获取之后创建bean时获取构造函数参数的值
Object value = parsePropertyValue(ele, bd, null);
// 根据value构造构造函数参数的值的对象ConstructorArgumentValues对象信息
ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
// 如果有type属性
if (StringUtils.hasLength(typeAttr)) {
valueHolder.setType(typeAttr);
}
// 如果有name属性
if (StringUtils.hasLength(nameAttr)) {
valueHolder.setName(nameAttr);
}
valueHolder.setSource(extractSource(ele));
// 判断存储构造函数索引位置->值 的map中是否已经存在索引位置
// 如果是存在则异常,即判断是否存在重复的index定义
if (bd.getConstructorArgumentValues().hasIndexedArgumentValue(index)) {
error("Ambiguous constructor-arg entries for index " + index, ele);
}
else {
// 存储构造函数参数索引位置->值 的信息到map中
bd.getConstructorArgumentValues().addIndexedArgumentValue(index, valueHolder);
}
}
finally {
this.parseState.pop();
}
}
}
catch (NumberFormatException ex) {
error("Attribute 'index' of tag 'constructor-arg' must be an integer", ele);
}
}
// 没有设置index的情况
else {
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));
// 存储值信息,这里和使用index的情况存储值的方式不一样
// index方式存储的是位置->值的信息,这存储的是name->值的信息
bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder);
}
finally {
this.parseState.pop();
}
}
}
<2021-03-05 11:19>
处是解析constructor-arg子元素和属性信息,源码:
org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parsePropertyValue
public Object parsePropertyValue(Element ele, BeanDefinition bd, @Nullable String propertyName) {
// 异常时给出提示信息使用
String elementName = (propertyName != null ?
"<property> element for property '" + propertyName + "'" :
"<constructor-arg> element");
// 给构造函数参数赋值的方式有以下几种
// 1:ref属性 2:value属性 3:ref子元素 4:value子元素 5:list子元素等
// 以下主要是判断赋值方式只能有一种,否则会冲突
NodeList nl = ele.getChildNodes();
Element subElement = null;
// 循环遍历constructor-arg的子元素
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)) {
// 如果是子元素已经不为空,说明你有多个子元素,这种情况直接异常
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);
// 以下的情况都会导致给构造函数参数赋值的冲突,直接异常
// 1:同时有ref属性和value属性
// 2: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属性
if (hasRefAttribute) {
// 获取ref的值
String refName = ele.getAttribute(REF_ATTRIBUTE);
// 如果是ref值没有内容则异常
if (!StringUtils.hasText(refName)) {
error(elementName + " contains empty 'ref' attribute", ele);
}
// 定义RuntimeBeanReference对象,封装ref的值信息
RuntimeBeanReference ref = new RuntimeBeanReference(refName);
ref.setSource(extractSource(ele));
// 返回封装有ref值信息的对象,之后用于给构造函数参数赋值使用
return ref;
}
// 有value属性
else if (hasValueAttribute) {
// 封装value的值到TypedStringValue对象中,并返回
TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));
valueHolder.setSource(extractSource(ele));
// 返回封装有value信息的对象,之后用于给构造函数参数赋值使用
return valueHolder;
}
// 如果是子元素的情况
else if (subElement != null) {
// <2021-03-05 13:24>
// 进一步解析子元素,获取能够给构造函数参数赋值的对象
return parsePropertySubElement(subElement, bd);
}
else {
error(elementName + " must specify a ref or value", ele);
return null;
}
}
<2021-03-05 13:24>
处是处理没有value和ref属性,而是通过子元素给构造函数参数提供值的情况,详细参考4.4.1:parsePropertySubElement
。
4.4.1:parsePropertySubElement
该方法通过constructor-arg的子标签来解析需要提供给构造函数参数的值,源码:
org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parsePropertySubElement(org.w3c.dom.Element, org.springframework.beans.factory.config.BeanDefinition)
public Object parsePropertySubElement(Element ele, @Nullable BeanDefinition bd) {
return parsePropertySubElement(ele, bd, null);
}
继续:
org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parsePropertySubElement(org.w3c.dom.Element, org.springframework.beans.factory.config.BeanDefinition, java.lang.String)
public Object parsePropertySubElement(Element ele, @Nullable BeanDefinition bd, @Nullable String defaultValueType) {
// 不是默认的命名空间,一般是
if (!isDefaultNamespace(ele)) {
return parseNestedCustomElement(ele, bd);
}
// 如果是bean标签,则调用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)) {
// 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.
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标签,应该是赋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;
}
}
根据不同的元素类型进行不同的解析,最终结果都是获取到可以给构造函数参数赋值的信息并返回。
4.5:property子标签解析
这种方式spring会通过无参构造函数来创建对象,然后根据property标签的配置调用对应的writter方法,给属性赋值。源码:
org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parsePropertyElements
public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
// 获取所有的子节点
NodeList nl = beanEle.getChildNodes();
// 循环处理所有的默认命名空间下的property元素
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) {
// <2021-03-05 15:20>
// 处理property元素
parsePropertyElement((Element) node, bd);
}
}
}
<2021-03-05 15:20>
处源码参考4.5.1:parsePropertyElement
。
4.5.1:parsePropertyElement
源码:
org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parsePropertyElement
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 {
// 判断重复的name值,存在则异常
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));
// 存储封装有"属性名称->属性值对象"的对象到beandefinition的
// 对应数据结构中
bd.getPropertyValues().addPropertyValue(pv);
}
finally {
this.parseState.pop();
}
}
4.6:qualifier子标签解析
暂时略。
5:bean自定义标签解析
关于自定义标签可以参考spring的自定义标签
,和spring通过自定义标签干预bean的生成过程
。
简单回顾下前面的流程,在方法org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#processBeanDefinition
中完成解析bean标签的工作,首先通过如下代码BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
完成解析默认标签的工作,然后接下就是解析自定义标签了,看下源码:
org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#processBeanDefinition
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 解析默认标签,返回BeanDefinitionHolder
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
// 如果不为空,解析自定义标签
if (bdHolder != null) {
// <2021-03-06 05:50>
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);
}
// 触发注册完成事件
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
<2021-03-06 05:50>
处注册自定义标签,源码:
org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#decorateBeanDefinitionIfRequired(org.w3c.dom.Element, org.springframework.beans.factory.config.BeanDefinitionHolder)
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder originalDef) {
return decorateBeanDefinitionIfRequired(ele, originalDef, null);
}
继续:
org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#decorateBeanDefinitionIfRequired(org.w3c.dom.Element, org.springframework.beans.factory.config.BeanDefinitionHolder, org.springframework.beans.factory.config.BeanDefinition)
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(
Element ele, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {
BeanDefinitionHolder finalDefinition = originalDef;
// 获取所有的属性,循环处理自定义属性
NamedNodeMap attributes = ele.getAttributes();
for (int i = 0; i < attributes.getLength(); i++) {
Node node = attributes.item(i);
finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
}
// 获取所有的子元素,循环处理所有的子元素
NodeList children = ele.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node node = children.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
// <2021-03-06 05:53>
finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
}
}
// 返回🈶经过自定义属性和自定义元素处理后的BeanDefinitionHolder
return finalDefinition;
}
<2021-03-06 05:53>
执行自定义标签的装饰,源码:
org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#decorateIfRequired
public BeanDefinitionHolder decorateIfRequired(
Node node, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {
// 获取命名空间,就是对应的xsd文件中的targetNamespace的值
String namespaceUri = getNamespaceURI(node);
// 不是默认命名空间即为自定义命名空间
if (namespaceUri != null && !isDefaultNamespace(namespaceUri)) {
// 通过命名空间获取处理对应标签的NamespaceHandler
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
// 有handler才处理
if (handler != null) {
// 调用处理器的decorate方法完成装饰,在该方法中我们可以完成自己的装饰逻辑了,当然这只是其中一种选择
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;
}
以上解析的自定义标签是作为bean标签的子标签存在的,如果不是作为bean标签的子标签而是和bean标签同级别的标签,这种自定义标签解析还没分析,接下来在spring是如何解析自定义标签的中分析下这种情况。