Spring源码学习(三)默认标签的解析

默认标签的解析
分为四种:import,alias,bean,beans,在下面函数中进行

 1     private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
 2         if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
 3             importBeanDefinitionResource(ele);
 4         }
 5         else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
 6             processAliasRegistration(ele);
 7         }
 8         else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
 9             processBeanDefinition(ele, delegate);
10         }
11         else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
12             // recurse
13             doRegisterBeanDefinitions(ele);
14         }
15     }
parseDefaultElement

 

先看bean标签的解析与注册的大致过程

//BeanDefinitionParserDelegate:定义解析Element的各种方法
    //BeanDefinitionHolder:Holder for a BeanDefinition with name and aliases.Can be registered as a placeholder for an inner bean.
    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if (bdHolder != null) {
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
            try {
                // Register the final decorated instance.
                BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
            }
            catch (BeanDefinitionStoreException ex) {
                getReaderContext().error("Failed to register bean definition with name '" +
                        bdHolder.getBeanName() + "'", ele, ex);
            }
            // Send registration event.
            getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }
    }
processBeanDefinition

(1)先调用BeanDefinitionParserDelegate.parseBeanDefinitionElement(),对xml中的各种属性进行解析,方法返回BeanDefinitionHolder类型的实例bdHolder

(2)bdHolder下有自定义标签则对自定义标签进行解析

(3)对bdHolder进行注册

 

元素解析大致过程

 1 @Nullable
 2     public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
 3         //获取id
 4         String id = ele.getAttribute(ID_ATTRIBUTE);
 5         //获取name
 6         String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
 7 
 8         List aliases = new ArrayList<>();
 9         if (StringUtils.hasLength(nameAttr)) {
10             String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
11             aliases.addAll(Arrays.asList(nameArr));
12         }
13 
14         String beanName = id;
15         if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
16             beanName = aliases.remove(0);
17             if (logger.isTraceEnabled()) {
18                 logger.trace("No XML 'id' specified - using '" + beanName +
19                         "' as bean name and " + aliases + " as aliases");
20             }
21         }
22 
23         //
24         if (containingBean == null) {
25             checkNameUniqueness(beanName, aliases, ele);
26         }
27 
28         //解析beanDefinition标签
29         AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
30         if (beanDefinition != null) {
31             if (!StringUtils.hasText(beanName)) {
32                 try {
33                     if (containingBean != null) {
34                         beanName = BeanDefinitionReaderUtils.generateBeanName(
35                                 beanDefinition, this.readerContext.getRegistry(), true);
36                     }
37                     else {
38                         beanName = this.readerContext.generateBeanName(beanDefinition);
39                         // Register an alias for the plain bean class name, if still possible,
40                         // if the generator returned the class name plus a suffix.
41                         // This is expected for Spring 1.2/2.0 backwards compatibility.
42                         String beanClassName = beanDefinition.getBeanClassName();
43                         if (beanClassName != null &&
44                                 beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
45                                 !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
46                             aliases.add(beanClassName);
47                         }
48                     }
49                     if (logger.isTraceEnabled()) {
50                         logger.trace("Neither XML 'id' nor 'name' specified - " +
51                                 "using generated bean name [" + beanName + "]");
52                     }
53                 }
54                 catch (Exception ex) {
55                     error(ex.getMessage(), ele);
56                     return null;
57                 }
58             }
59             String[] aliasesArray = StringUtils.toStringArray(aliases);
60             return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
61         }
62 
63         return null;
64     }
parseBeanDefinitionElement

(1)获取标签中的id,name属性,当name不为空情况下获取其aliases

(2)解析其他的属性封装在AbstractBeanDefinition中并返回实例beanDefinition

(3)当bean无id属性则按照默认规则为其生成,并校验是否添加至aliases

(4)将beanDefinition,beanName,获取的aliases的aliasesArray封装至BeanDefinitionHolder中

 

具体解析了哪些其他标签

 1 @Nullable
 2     public AbstractBeanDefinition parseBeanDefinitionElement(
 3             Element ele, String beanName, @Nullable BeanDefinition containingBean) {
 4 
 5         this.parseState.push(new BeanEntry(beanName));
 6 
 7         String className = null;
 8         if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
 9             className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
10         }
11         String parent = null;
12         if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
13             parent = ele.getAttribute(PARENT_ATTRIBUTE);
14         }
15 
16         try {
17             //创建GenericBeanDefinition类型的实例,用于承载属性的实例
18             AbstractBeanDefinition bd = createBeanDefinition(className, parent);
19 
20             //解析bean默认的各种属性
21             parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
22             bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
23 
24             //解析元数据
25             parseMetaElements(ele, bd);
26             //解析lookup-method方法
27             parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
28             //解析replaced-method方法
29             parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
30 
31             //解析构造函数
32             parseConstructorArgElements(ele, bd);
33             //解析Property
34             parsePropertyElements(ele, bd);
35             //解析Qualifier
36             parseQualifierElements(ele, bd);
37 
38             bd.setResource(this.readerContext.getResource());
39             bd.setSource(extractSource(ele));
40 
41             return bd;
42         }
43         catch (ClassNotFoundException ex) {
44             error("Bean class [" + className + "] not found", ele, ex);
45         }
46         catch (NoClassDefFoundError err) {
47             error("Class that bean class [" + className + "] depends on not found", ele, err);
48         }
49         catch (Throwable ex) {
50             error("Unexpected failure during bean definition parsing", ele, ex);
51         }
52         finally {
53             this.parseState.pop();
54         }
55 
56         return null;
57     }
parseBeanDefinitionElement

 

bean的各种属性

 1 /**
 2      * Apply the attributes of the given bean element to the given bean * definition.
 3      * @param ele bean declaration element
 4      * @param beanName bean name
 5      * @param containingBean containing bean definition
 6      * @return a bean definition initialized according to the bean element attributes
 7      */
 8     public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
 9             @Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) {
10 
11         if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
12             error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);
13         }
14         else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) {
15             bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));
16         }
17         else if (containingBean != null) {
18             // Take default from containing bean in case of an inner bean definition.
19             // 如果是内部bean定义,则从包含bean中获取默认值。
20             bd.setScope(containingBean.getScope());
21         }
22 
23         if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {
24             bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
25         }
26 
27         String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
28         if (isDefaultValue(lazyInit)) {
29             lazyInit = this.defaults.getLazyInit();
30         }
31         bd.setLazyInit(TRUE_VALUE.equals(lazyInit));
32 
33         String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
34         bd.setAutowireMode(getAutowireMode(autowire));
35 
36         if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) {
37             String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE);
38             bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS));
39         }
40 
41         String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE);
42         if (isDefaultValue(autowireCandidate)) {
43             String candidatePattern = this.defaults.getAutowireCandidates();
44             if (candidatePattern != null) {
45                 String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern);
46                 bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
47             }
48         }
49         else {
50             bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate));
51         }
52 
53         if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) {
54             bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE)));
55         }
56 
57         if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) {
58             String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE);
59             bd.setInitMethodName(initMethodName);
60         }
61         else if (this.defaults.getInitMethod() != null) {
62             bd.setInitMethodName(this.defaults.getInitMethod());
63             bd.setEnforceInitMethod(false);
64         }
65 
66         if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) {
67             String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE);
68             bd.setDestroyMethodName(destroyMethodName);
69         }
70         else if (this.defaults.getDestroyMethod() != null) {
71             bd.setDestroyMethodName(this.defaults.getDestroyMethod());
72             bd.setEnforceDestroyMethod(false);
73         }
74 
75         if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) {
76             bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE));
77         }
78         if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {
79             bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE));
80         }
81 
82         return bd;
83     }
parseBeanDefinitionAttributes

 

 具体看解析子元素meta标签

 1 public void parseMetaElements(Element ele, BeanMetadataAttributeAccessor attributeAccessor) {
 2         NodeList nl = ele.getChildNodes();
 3         for (int i = 0; i < nl.getLength(); i++) {
 4             Node node = nl.item(i);
 5             if (isCandidateElement(node) && nodeNameEquals(node, META_ELEMENT)) {
 6                 Element metaElement = (Element) node;
 7                 String key = metaElement.getAttribute(KEY_ATTRIBUTE);
 8                 String value = metaElement.getAttribute(VALUE_ATTRIBUTE);
 9                 BeanMetadataAttribute attribute = new BeanMetadataAttribute(key, value);
10                 attribute.setSource(extractSource(metaElement));
11                 attributeAccessor.addMetadataAttribute(attribute);
12             }
13         }
14     }
parseMetaElements
1     <bean id="tiger" class="com.vi.springbean.Tiger">
2         <meta key="tigerKey" value="hello"/>
3     bean>
eg:xml

 

具体看解析子元素lookup-method标签

 1     public void parseLookupOverrideSubElements(Element beanEle, MethodOverrides overrides) {
 2         NodeList nl = beanEle.getChildNodes();
 3         for (int i = 0; i < nl.getLength(); i++) {
 4             Node node = nl.item(i);
 5             if (isCandidateElement(node) && nodeNameEquals(node, LOOKUP_METHOD_ELEMENT)) {
 6                 Element ele = (Element) node;
 7                 // ="" bean=""/>
 8                 String methodName = ele.getAttribute(NAME_ATTRIBUTE);
 9                 String beanRef = ele.getAttribute(BEAN_ELEMENT);
10                 LookupOverride override = new LookupOverride(methodName, beanRef);
11                 override.setSource(extractSource(ele));
12                 overrides.addOverride(override);
13             }
14         }
15     }
parseLookupOverrideSubElements

其实和meta标签解析大同小异

看一下lookup-method标签具体如何使用

1 public class Animal {
2     public void sayHello(){
3         System.out.println("hello ··");
4     }
5 }
父类
1 public class Tiger extends Animal {
2 
3     @Override
4     public void sayHello() {
5         System.out.println("hello  我是王者");
6     }
7 }
子类
1 public class Mouse extends Animal{
2     @Override
3     public void sayHello() {
4         System.out.println("hello 我是生肖之首");
5     }
6 }
子类
1 public abstract class LookUpTest {
2 
3     public abstract Animal getBean();
4 
5     public  void say(){
6         this.getBean().sayHello();
7     }
8 }
调用方法
1 public class Test {
2     @org.junit.Test
3     public void test() {
4         String path = "spring-config.xml";
5         ApplicationContext bf = new ClassPathXmlApplicationContext(path);
6         LookUpTest bean = bf.getBean(LookUpTest.class);
7         bean.say();
8     }
9 }
测试方法

当xml配置如下:

 1 xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4        xsi:schemaLocation="http://www.springframework.org/schema/beans
 5        http://www.springframework.org/schema/beans/spring-beans.xsd">
 6 
 7     <bean id="lookUpTest" class="com.vi.springbean.LookUpTest">
 8         <lookup-method name="getBean" bean="tiger">lookup-method>
 9     bean>
10 
11     <bean id="mouse" class="com.vi.springbean.Mouse">bean>
12     <bean id="tiger" class="com.vi.springbean.Tiger">bean>
13 
14 beans>
xml配置0

运行结果:

hello 我是动物之王

当xml配置如下

 1 xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4        xsi:schemaLocation="http://www.springframework.org/schema/beans
 5        http://www.springframework.org/schema/beans/spring-beans.xsd">
 6 
 7     <bean id="lookUpTest" class="com.vi.springbean.LookUpTest">
 8         <lookup-method name="getBean" bean="mouse">lookup-method>
 9     bean>
10 
11     <bean id="mouse" class="com.vi.springbean.Mouse">bean>
12     <bean id="tiger" class="com.vi.springbean.Tiger">bean>
13 
14 beans>
xml配置1

运行结果:

hello 我是生肖之首

这个配置完成的功能就是通过更改xml中lookup-method的配置,bean对应的对象作为getBean的返回

这是一种特殊的注入方式,被称为获取器注入,他是把一个方法声明为返回某种类型的bean,但实际要返回的bean是在xml文件中配置的。

好处是看解决程序依赖

具体看解析子元素replaced-method标签 

 1 /**
 2      * Parse replaced-method sub-elements of the given bean element.
 3      */
 4     public void parseReplacedMethodSubElements(Element beanEle, MethodOverrides overrides) {
 5         NodeList nl = beanEle.getChildNodes();
 6         for (int i = 0; i < nl.getLength(); i++) {
 7             Node node = nl.item(i);
 8             if (isCandidateElement(node) && nodeNameEquals(node, REPLACED_METHOD_ELEMENT)) {
 9                 Element replacedMethodEle = (Element) node;
10                 // 
11                 String name = replacedMethodEle.getAttribute(NAME_ATTRIBUTE);
12                 String callback = replacedMethodEle.getAttribute(REPLACER_ATTRIBUTE);
13                 ReplaceOverride replaceOverride = new ReplaceOverride(name, callback);
14                 // Look for arg-type match elements.
15                 List argTypeEles = DomUtils.getChildElementsByTagName(replacedMethodEle, ARG_TYPE_ELEMENT);
16                 for (Element argTypeEle : argTypeEles) {
17                     String match = argTypeEle.getAttribute(ARG_TYPE_MATCH_ATTRIBUTE);
18                     match = (StringUtils.hasText(match) ? match : DomUtils.getTextValue(argTypeEle));
19                     if (StringUtils.hasText(match)) {
20                         replaceOverride.addTypeIdentifier(match);
21                     }
22                 }
23                 replaceOverride.setSource(extractSource(replacedMethodEle));
24                 overrides.addOverride(replaceOverride);
25             }
26         }
27     }
parseReplacedMethodSubElements

看一下replaced-method标签具体如何使用

1 public class Replacer {
2     public void changeMe(){
3         System.out.println("hello please change me");
4     }
5 }
待替换方法
1 public class ReplaceTest implements MethodReplacer {
2     @Override
3     public Object reimplement(Object obj, Method method, Object[] args) throws Throwable {
4         System.out.println("每个人都将成为王者");
5         return null;
6     }
7 }
替换的方法实现
 1 xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4        xsi:schemaLocation="http://www.springframework.org/schema/beans
 5        http://www.springframework.org/schema/beans/spring-beans.xsd">
 6 
 7     <bean id="replacer" class="com.vi.springbean.Replacer">
 8         <replaced-method name="changeMe" replacer="replaceTest">replaced-method>
 9     bean>
10 
11     <bean id="replaceTest" class="com.vi.springbean.ReplaceTest">bean>
12 
13 beans>
xml配置
1 public class Test {
2     @org.junit.Test
3     public void test() {
4         String path = "spring-config.xml";
5         ApplicationContext bf = new ClassPathXmlApplicationContext(path);
6         Replacer bean = bf.getBean(Replacer.class);
7         bean.changeMe();
8     }
9 }
Test类

运行结果:

每个人都将成为王者

 

解析子元素constructor-arg

 

 1     /**
 2      * Parse constructor-arg sub-elements of the given bean element.
 3      */
 4     public void parseConstructorArgElements(Element beanEle, BeanDefinition bd) {
 5         NodeList nl = beanEle.getChildNodes();
 6         for (int i = 0; i < nl.getLength(); i++) {
 7             Node node = nl.item(i);
 8             if (isCandidateElement(node) && nodeNameEquals(node, CONSTRUCTOR_ARG_ELEMENT)) {
 9                 parseConstructorArgElement((Element) node, bd);
10             }
11         }
12     }
parseConstructorArgElements

 

 1 public void parseConstructorArgElement(Element ele, BeanDefinition bd) {
 2         String indexAttr = ele.getAttribute(INDEX_ATTRIBUTE);
 3         String typeAttr = ele.getAttribute(TYPE_ATTRIBUTE);
 4         String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
 5         if (StringUtils.hasLength(indexAttr)) {
 6             try {
 7                 int index = Integer.parseInt(indexAttr);
 8                 if (index < 0) {
 9                     error("'index' cannot be lower than 0", ele);
10                 }
11                 else {
12                     try {
13                         this.parseState.push(new ConstructorArgumentEntry(index));
14                         Object value = parsePropertyValue(ele, bd, null);
15                         ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
16                         if (StringUtils.hasLength(typeAttr)) {
17                             valueHolder.setType(typeAttr);
18                         }
19                         if (StringUtils.hasLength(nameAttr)) {
20                             valueHolder.setName(nameAttr);
21                         }
22                         valueHolder.setSource(extractSource(ele));
23                         if (bd.getConstructorArgumentValues().hasIndexedArgumentValue(index)) {
24                             error("Ambiguous constructor-arg entries for index " + index, ele);
25                         }
26                         else {
27                             bd.getConstructorArgumentValues().addIndexedArgumentValue(index, valueHolder);
28                         }
29                     }
30                     finally {
31                         this.parseState.pop();
32                     }
33                 }
34             }
35             catch (NumberFormatException ex) {
36                 error("Attribute 'index' of tag 'constructor-arg' must be an integer", ele);
37             }
38         }
39         else {
40             try {
41                 this.parseState.push(new ConstructorArgumentEntry());
42                 Object value = parsePropertyValue(ele, bd, null);
43                 ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
44                 if (StringUtils.hasLength(typeAttr)) {
45                     valueHolder.setType(typeAttr);
46                 }
47                 if (StringUtils.hasLength(nameAttr)) {
48                     valueHolder.setName(nameAttr);
49                 }
50                 valueHolder.setSource(extractSource(ele));
51                 bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder);
52             }
53             finally {
54                 this.parseState.pop();
55             }
56         }
57     }
parseConstructorArgElement

当配置中指定了index属性

(1)获取index值,且检验index值不能小于0,且需未integer类型

(2)获取value,type,name值,并封装在ConstructorArgumentValues.ValueHolder的实例valueHolder中

(3)不能重复指定相同index属性下的值

(4)以index,valueHolder(key,value)的形式添加到当前的BeanDefinition的ConstructorArgumentValues的indexedArgumentValues(是一个map)中

 

当配置中未指定index属性

(1) 获取value,type,name值,并封装在ConstructorArgumentValues.ValueHolder的实例valueHolder中

(2)添加至ConstructorArgumentValues的genericArgumentValues中

 

可见根据有无index属在最终存储位置,形式不一样

1 private final Map indexedArgumentValues = new LinkedHashMap<>();
2 
3 private final List genericArgumentValues = new ArrayList<>();

parsePropertyValue方法
 1     /**
 2      * Get the value of a property element. May be a list etc.
 3      * Also used for constructor arguments, "propertyName" being null in this case.
 4      */
 5     @Nullable
 6     public Object parsePropertyValue(Element ele, BeanDefinition bd, @Nullable String propertyName) {
 7         String elementName = (propertyName != null ?
 8                 " element for property '" + propertyName + "'" :
 9                 " element");
10 
11         // Should only have one child element: ref, value, list, etc.
12         NodeList nl = ele.getChildNodes();
13         Element subElement = null;
14         for (int i = 0; i < nl.getLength(); i++) {
15             Node node = nl.item(i);
16             // 对于description,meta属性不做处理
17             if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) &&
18                     !nodeNameEquals(node, META_ELEMENT)) {
19                 // Child element is what we're looking for.
20                 if (subElement != null) {
21                     error(elementName + " must not contain more than one sub-element", ele);
22                 }
23                 else {
24                     subElement = (Element) node;
25                 }
26             }
27         }
28 
29         boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
30         boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
31         // ref,value属性不能同时存在,且都不能有子元素
32         if ((hasRefAttribute && hasValueAttribute) ||
33                 ((hasRefAttribute || hasValueAttribute) && subElement != null)) {
34             error(elementName +
35                     " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);
36         }
37 
38         if (hasRefAttribute) {
39             String refName = ele.getAttribute(REF_ATTRIBUTE);
40             if (!StringUtils.hasText(refName)) {
41                 error(elementName + " contains empty 'ref' attribute", ele);
42             }
43             RuntimeBeanReference ref = new RuntimeBeanReference(refName);
44             ref.setSource(extractSource(ele));
45             return ref;
46         }
47         else if (hasValueAttribute) {
48             TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));
49             valueHolder.setSource(extractSource(ele));
50             return valueHolder;
51         }
52         else if (subElement != null) {
53             return parsePropertySubElement(subElement, bd);
54         }
55         else {
56             // Neither child element nor "ref" or "value" attribute found.
57             error(elementName + " must specify a ref or value", ele);
58             return null;
59         }
60     }
parsePropertyValue

(1)对于构造函数中子元素的解析是跳过meta,description属性

(2)ref,value属性不能同时存在,且ref,value都不能有子元素

(3)或解析ref标签,封装至RuntimeBeanReference中

(4)或解析value标签,封装至TypedStringValue中

(5)或解析子元素便签(接下来看这个是怎么实现的)

 

 解析子元素便签

 

 1     /**
 2      * Parse a value, ref or collection sub-element of a property or
 3      * constructor-arg element.
 4      * @param ele subelement of property element; we don't know which yet
 5      * @param bd the current bean definition (if any)
 6      */
 7     @Nullable
 8     public Object parsePropertySubElement(Element ele, @Nullable BeanDefinition bd) {
 9         return parsePropertySubElement(ele, bd, null);
10     }
parsePropertySubElement

 

 1     /**
 2      * Parse a value, ref or collection sub-element of a property or
 3      * constructor-arg element.
 4      * @param ele subelement of property element; we don't know which yet
 5      * @param bd the current bean definition (if any)
 6      * @param defaultValueType the default type (class name) for any
 7      * {@code } tag that might be created
 8      */
 9     @Nullable
10     public Object parsePropertySubElement(Element ele, @Nullable BeanDefinition bd, @Nullable String defaultValueType) {
11         if (!isDefaultNamespace(ele)) {
12             return parseNestedCustomElement(ele, bd);
13         }
14         else if (nodeNameEquals(ele, BEAN_ELEMENT)) {
15             BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd);
16             if (nestedBd != null) {
17                 nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd);
18             }
19             return nestedBd;
20         }
21         else if (nodeNameEquals(ele, REF_ELEMENT)) {
22             // A generic reference to any name of any bean.
23             String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE);
24             boolean toParent = false;
25             if (!StringUtils.hasLength(refName)) {
26                 // A reference to the id of another bean in a parent context.
27                 refName = ele.getAttribute(PARENT_REF_ATTRIBUTE);
28                 toParent = true;
29                 if (!StringUtils.hasLength(refName)) {
30                     error("'bean' or 'parent' is required for  element", ele);
31                     return null;
32                 }
33             }
34             if (!StringUtils.hasText(refName)) {
35                 error(" element contains empty target attribute", ele);
36                 return null;
37             }
38             RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent);
39             ref.setSource(extractSource(ele));
40             return ref;
41         }
42         else if (nodeNameEquals(ele, IDREF_ELEMENT)) {
43             return parseIdRefElement(ele);
44         }
45         else if (nodeNameEquals(ele, VALUE_ELEMENT)) {
46             return parseValueElement(ele, defaultValueType);
47         }
48         else if (nodeNameEquals(ele, NULL_ELEMENT)) {
49             // It's a distinguished null value. Let's wrap it in a TypedStringValue
50             // object in order to preserve the source location.
51             TypedStringValue nullHolder = new TypedStringValue(null);
52             nullHolder.setSource(extractSource(ele));
53             return nullHolder;
54         }
55         else if (nodeNameEquals(ele, ARRAY_ELEMENT)) {
56             return parseArrayElement(ele, bd);
57         }
58         else if (nodeNameEquals(ele, LIST_ELEMENT)) {
59             return parseListElement(ele, bd);
60         }
61         else if (nodeNameEquals(ele, SET_ELEMENT)) {
62             return parseSetElement(ele, bd);
63         }
64         else if (nodeNameEquals(ele, MAP_ELEMENT)) {
65             return parseMapElement(ele, bd);
66         }
67         else if (nodeNameEquals(ele, PROPS_ELEMENT)) {
68             return parsePropsElement(ele);
69         }
70         else {
71             error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele);
72             return null;
73         }
74     }
parsePropertySubElement

 

子元素map标签解析(TODO)

  1     /**
  2      * Parse a map element.
  3      */
  4     public Map parseMapElement(Element mapEle, @Nullable BeanDefinition bd) {
  5         String defaultKeyType = mapEle.getAttribute(KEY_TYPE_ATTRIBUTE);
  6         String defaultValueType = mapEle.getAttribute(VALUE_TYPE_ATTRIBUTE);
  7 
  8         List entryEles = DomUtils.getChildElementsByTagName(mapEle, ENTRY_ELEMENT);
  9         ManagedMap map = new ManagedMap<>(entryEles.size());
 10         map.setSource(extractSource(mapEle));
 11         map.setKeyTypeName(defaultKeyType);
 12         map.setValueTypeName(defaultValueType);
 13         map.setMergeEnabled(parseMergeAttribute(mapEle));
 14 
 15         for (Element entryEle : entryEles) {
 16             // Should only have one value child element: ref, value, list, etc.
 17             // Optionally, there might be a key child element.
 18             NodeList entrySubNodes = entryEle.getChildNodes();
 19             Element keyEle = null;
 20             Element valueEle = null;
 21             for (int j = 0; j < entrySubNodes.getLength(); j++) {
 22                 Node node = entrySubNodes.item(j);
 23                 if (node instanceof Element) {
 24                     Element candidateEle = (Element) node;
 25                     if (nodeNameEquals(candidateEle, KEY_ELEMENT)) {
 26                         if (keyEle != null) {
 27                             error(" element is only allowed to contain one  sub-element", entryEle);
 28                         }
 29                         else {
 30                             keyEle = candidateEle;
 31                         }
 32                     }
 33                     else {
 34                         // Child element is what we're looking for.
 35                         if (nodeNameEquals(candidateEle, DESCRIPTION_ELEMENT)) {
 36                             // the element is a  -> ignore it
 37                         }
 38                         else if (valueEle != null) {
 39                             error(" element must not contain more than one value sub-element", entryEle);
 40                         }
 41                         else {
 42                             valueEle = candidateEle;
 43                         }
 44                     }
 45                 }
 46             }
 47 
 48             // Extract key from attribute or sub-element.
 49             Object key = null;
 50             boolean hasKeyAttribute = entryEle.hasAttribute(KEY_ATTRIBUTE);
 51             boolean hasKeyRefAttribute = entryEle.hasAttribute(KEY_REF_ATTRIBUTE);
 52             if ((hasKeyAttribute && hasKeyRefAttribute) ||
 53                     (hasKeyAttribute || hasKeyRefAttribute) && keyEle != null) {
 54                 error(" element is only allowed to contain either " +
 55                         "a 'key' attribute OR a 'key-ref' attribute OR a  sub-element", entryEle);
 56             }
 57             if (hasKeyAttribute) {
 58                 key = buildTypedStringValueForMap(entryEle.getAttribute(KEY_ATTRIBUTE), defaultKeyType, entryEle);
 59             }
 60             else if (hasKeyRefAttribute) {
 61                 String refName = entryEle.getAttribute(KEY_REF_ATTRIBUTE);
 62                 if (!StringUtils.hasText(refName)) {
 63                     error(" element contains empty 'key-ref' attribute", entryEle);
 64                 }
 65                 RuntimeBeanReference ref = new RuntimeBeanReference(refName);
 66                 ref.setSource(extractSource(entryEle));
 67                 key = ref;
 68             }
 69             else if (keyEle != null) {
 70                 key = parseKeyElement(keyEle, bd, defaultKeyType);
 71             }
 72             else {
 73                 error(" element must specify a key", entryEle);
 74             }
 75 
 76             // Extract value from attribute or sub-element.
 77             Object value = null;
 78             boolean hasValueAttribute = entryEle.hasAttribute(VALUE_ATTRIBUTE);
 79             boolean hasValueRefAttribute = entryEle.hasAttribute(VALUE_REF_ATTRIBUTE);
 80             boolean hasValueTypeAttribute = entryEle.hasAttribute(VALUE_TYPE_ATTRIBUTE);
 81             if ((hasValueAttribute && hasValueRefAttribute) ||
 82                     (hasValueAttribute || hasValueRefAttribute) && valueEle != null) {
 83                 error(" element is only allowed to contain either " +
 84                         "'value' attribute OR 'value-ref' attribute OR  sub-element", entryEle);
 85             }
 86             if ((hasValueTypeAttribute && hasValueRefAttribute) ||
 87                 (hasValueTypeAttribute && !hasValueAttribute) ||
 88                     (hasValueTypeAttribute && valueEle != null)) {
 89                 error(" element is only allowed to contain a 'value-type' " +
 90                         "attribute when it has a 'value' attribute", entryEle);
 91             }
 92             if (hasValueAttribute) {
 93                 String valueType = entryEle.getAttribute(VALUE_TYPE_ATTRIBUTE);
 94                 if (!StringUtils.hasText(valueType)) {
 95                     valueType = defaultValueType;
 96                 }
 97                 value = buildTypedStringValueForMap(entryEle.getAttribute(VALUE_ATTRIBUTE), valueType, entryEle);
 98             }
 99             else if (hasValueRefAttribute) {
100                 String refName = entryEle.getAttribute(VALUE_REF_ATTRIBUTE);
101                 if (!StringUtils.hasText(refName)) {
102                     error(" element contains empty 'value-ref' attribute", entryEle);
103                 }
104                 RuntimeBeanReference ref = new RuntimeBeanReference(refName);
105                 ref.setSource(extractSource(entryEle));
106                 value = ref;
107             }
108             else if (valueEle != null) {
109                 value = parsePropertySubElement(valueEle, bd, defaultValueType);
110             }
111             else {
112                 error(" element must specify a value", entryEle);
113             }
114 
115             // Add final key and value to the Map.
116             map.put(key, value);
117         }
118 
119         return map;
120     }
parseMapElement
 
 

 

解析子元素property

 

 1      * Parse property sub-elements of the given bean element.
 2      */
 3     public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
 4         NodeList nl = beanEle.getChildNodes();
 5         for (int i = 0; i < nl.getLength(); i++) {
 6             Node node = nl.item(i);
 7             if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) {
 8                 parsePropertyElement((Element) node, bd);
 9             }
10         }
11     }
parsePropertyElements

 

 1 /**
 2      * Parse a property element.
 3      */
 4     public void parsePropertyElement(Element ele, BeanDefinition bd) {
 5         String propertyName = ele.getAttribute(NAME_ATTRIBUTE);
 6         if (!StringUtils.hasLength(propertyName)) {
 7             error("Tag 'property' must have a 'name' attribute", ele);
 8             return;
 9         }
10         this.parseState.push(new PropertyEntry(propertyName));
11         try {
12             if (bd.getPropertyValues().contains(propertyName)) {
13                 error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
14                 return;
15             }
16             Object val = parsePropertyValue(ele, bd, propertyName);
17             PropertyValue pv = new PropertyValue(propertyName, val);
18             parseMetaElements(ele, pv);
19             pv.setSource(extractSource(ele));
20             bd.getPropertyValues().addPropertyValue(pv);
21         }
22         finally {
23             this.parseState.pop();
24         }
25     }
parsePropertyElement

 

 

 

注:
GenericBeanDefinition,ChildBeanDefinition,RootBeanDefinition 都继承AbstractBeanDefinition
AbstractBeanDefinition 继承 BeanMetadataAttributeAccessor 实现 BeanDefinition

------------------------------------------------------------------------------------------------------------------------------

------------------------------------------------------------------------------------------------------------------------------

 解析默认标签中的自定义标签元素

1     /**
2      * Decorate the given bean definition through a namespace handler, if applicable.
3      * @param ele the current element
4      * @param originalDef the current bean definition
5      * @return the decorated bean definition
6      */
7     public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder originalDef) {
8         return decorateBeanDefinitionIfRequired(ele, originalDef, null);
9     }
decorateBeanDefinitionIfRequired

 

 1     /**
 2      * Decorate the given bean definition through a namespace handler, if applicable.
 3      * @param ele the current element
 4      * @param originalDef the current bean definition
 5      * @param containingBd the containing bean definition (if any)
 6      * @return the decorated bean definition
 7      */
 8     public BeanDefinitionHolder decorateBeanDefinitionIfRequired(
 9             Element ele, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {
10 
11         BeanDefinitionHolder finalDefinition = originalDef;
12 
13         // Decorate based on custom attributes first.
14         NamedNodeMap attributes = ele.getAttributes();
15         for (int i = 0; i < attributes.getLength(); i++) {
16             Node node = attributes.item(i);
17             finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
18         }
19 
20         // Decorate based on custom nested elements.
21         NodeList children = ele.getChildNodes();
22         for (int i = 0; i < children.getLength(); i++) {
23             Node node = children.item(i);
24             if (node.getNodeType() == Node.ELEMENT_NODE) {
25                 finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
26             }
27         }
28         return finalDefinition;
29     }
decorateBeanDefinitionIfRequired

(1)对所有的我属性

(2)对于所有的子节点

 

 1     /**
 2      * Decorate the given bean definition through a namespace handler,
 3      * if applicable.
 4      * @param node the current child node
 5      * @param originalDef the current bean definition
 6      * @param containingBd the containing bean definition (if any)
 7      * @return the decorated bean definition
 8      */
 9     public BeanDefinitionHolder decorateIfRequired(
10             Node node, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {
11 
12         String namespaceUri = getNamespaceURI(node);
13         if (namespaceUri != null && !isDefaultNamespace(namespaceUri)) {
14             NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
15             if (handler != null) {
16                 BeanDefinitionHolder decorated =
17                         handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd));
18                 if (decorated != null) {
19                     return decorated;
20                 }
21             }
22             else if (namespaceUri.startsWith("http://www.springframework.org/")) {
23                 error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", node);
24             }
25             else {
26                 // A custom namespace, not to be handled by Spring - maybe "xml:...".
27                 if (logger.isDebugEnabled()) {
28                     logger.debug("No Spring NamespaceHandler found for XML schema namespace [" + namespaceUri + "]");
29                 }
30             }
31         }
32         return originalDef;
33     }
decorateIfRequired

(1)可以看出是根据命名空间判断是否适用于自定义标签的解析条件的

 

注册已解析的BeanDefinition

 1     /**
 2      * Register the given bean definition with the given bean factory.
 3      * @param definitionHolder the bean definition including name and aliases
 4      * @param registry the bean factory to register with
 5      * @throws BeanDefinitionStoreException if registration failed
 6      */
 7     public static void registerBeanDefinition(
 8             BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
 9             throws BeanDefinitionStoreException {
10 
11         // Register bean definition under primary name.
12         String beanName = definitionHolder.getBeanName();
13         registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
14 
15         // Register aliases for bean name, if any.
16         String[] aliases = definitionHolder.getAliases();
17         if (aliases != null) {
18             for (String alias : aliases) {
19                 registry.registerAlias(beanName, alias);
20             }
21         }
22     }
registerBeanDefinition

(1)通过beanName注册

(2)通过别名注册

 

 

了解alias标签的解析

TODO

了解import标签的解析

TODO

 

了解beans标签的解析

递归调用beans标签的解析过程

 



已经是2020年的第二天了 时间过的很快 或许只有我一人觉得19年自己碌碌无为 20年加油吧

 

你可能感兴趣的:(Spring源码学习(三)默认标签的解析)