SpringIOC-默认标签解析
默认标签解析
parseDefaultElement
接着上文,调用parseDefaultElement主要负责默认标签的解析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 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)) { doRegisterBeanDefinitions(ele); } }
我们主要看processBeanDefinition,bean标签的解析,doRegisterBeanDefinitions主要负责beans标签解析,他的流程很简单,又重新调回了doRegisterBeanDefinitions重新开始解析
可以看到默认命名空间的一级节点只有4种:import、alias、bean、beans。这4种节点中,最重要、最复杂的就是 <bean> 节点,本文只会介绍 <bean> 节点的处理,理解了 <bean> 节点后,其他的都不难理解。另外,<beans> 节点只是递归调用之前的 doRegisterBeanDefinitions 方法,因此无需再介绍。
接下来,让我们从 processBeanDefinition(ele, delegate) 方法正式开始
processBeanDefinition
解析bean标签 委托模式主要对<bean />这一类标签解析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 protected void processBeanDefinition (Element ele, BeanDefinitionParserDelegate delegate) { BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null ) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { 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)); } }
核心方法是parseBeanDefinitionElement,解析bean的各种元素
parseBeanDefinitionElement
bean标签的解析,将标签元素转成BeanDefinitionHolder
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 @Nullable public BeanDefinitionHolder parseBeanDefinitionElement (Element ele) { return parseBeanDefinitionElement(ele, null ); } @Nullable public BeanDefinitionHolder parseBeanDefinitionElement (Element ele, @Nullable BeanDefinition containingBean) { String id = ele.getAttribute(ID_ATTRIBUTE); String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); List<String> aliases = new ArrayList <>(); if (StringUtils.hasLength(nameAttr)) { String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS); aliases.addAll(Arrays.asList(nameArr)); } String beanName = id; if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) { beanName = aliases.remove(0 ); if (logger.isTraceEnabled()) { logger.trace("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); 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); return new BeanDefinitionHolder (beanDefinition, beanName, aliasesArray); } return null ; }
这里的核心方法是parseBeanDefinitionElement解析bean标签的各种元素
解析 name 和 id 属性,其中 name 属性可以通过分割符设置多个。如果 id 存在,则 使用 id 作为 beanName,name 属性分割后全部作为别名;如果 id 不存在,则将 name 属性分割后的第1个作为 beanName,剩下的全部作为别名。
举个例子:
1 2 3 4 5 <bean id ="appleService" name ="appleOne;appleTwo" class ="com.joonwhee.AppleServiceImpl" /> <bean name ="bananaOne;bananaTwo" class ="com.joonwhee.BananaServiceImpl" />
配置1:beanName=appleService,aliases=[appleOne, appleTwo] ;
配置2:beanName=bananaOne,aliases=[bananaTwo]
parseBeanDefinitionElement
将Element 元素解析成 BeanDefinition,然后并将解析完成的BeanDefinition返回
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 @Nullable public AbstractBeanDefinition parseBeanDefinitionElement ( Element ele, String beanName, @Nullable BeanDefinition containingBean) { this .parseState.push(new BeanEntry (beanName)); String className = null ; if (ele.hasAttribute(CLASS_ATTRIBUTE)) { className = ele.getAttribute(CLASS_ATTRIBUTE).trim(); } String parent = null ; if (ele.hasAttribute(PARENT_ATTRIBUTE)) { parent = ele.getAttribute(PARENT_ATTRIBUTE); } try { AbstractBeanDefinition bd = createBeanDefinition(className, parent); parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT)); parseMetaElements(ele, bd); parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); parseConstructorArgElements(ele, bd); parsePropertyElements(ele, bd); 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 ; }
1.解析了class、parent属性,因为第2步创建 AbstractBeanDefinition 需要用到这两个属性,否则,这两个属性可以放到第3步一起解析。
2.创建用于承载属性的 AbstractBeanDefinition 类型的 GenericBeanDefinition。比较简单,直接 new 一个 GenericBeanDefinition,如果 className 和 classLoader 不为空,则通过反射构建出 BeanClass,并设置为 GenericBeanDefinition 的属性。
createBeanDefinition
来到BeanDefinitionReaderUtils类中
创建GenericBeanDefinition对象并进行parentName,beanClass等属性的初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 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; }
解析标签元素
这里面涉及很多标签的解析,我们下面会对几个比较重要的分析一下
parseBeanDefinitionAttributes
解析bean标签的属性,并把解析出来的属性设置到BeanDefinition对象中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 public AbstractBeanDefinition parseBeanDefinitionAttributes (Element ele, String beanName, @Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) { if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) { error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration" , ele); } else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) { bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE)); } else if (containingBean != null ) { bd.setScope(containingBean.getScope()); } if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) { bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE))); } String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE); if (isDefaultValue(lazyInit)) { lazyInit = this .defaults.getLazyInit(); } bd.setLazyInit(TRUE_VALUE.equals(lazyInit)); String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE); bd.setAutowireMode(getAutowireMode(autowire)); if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) { String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE); bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS)); } String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE); if (isDefaultValue(autowireCandidate)) { String candidatePattern = this .defaults.getAutowireCandidates(); if (candidatePattern != null ) { String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern); bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName)); } } else { bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate)); } if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) { bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE))); } 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 ); } 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 ); } if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) { bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE)); } if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) { bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE)); } return bd; }
内容比较简单,就是从节点 ele 拿到所有的属性值,塞给 AbstractBeanDefinition 的对应属性。这些属性的使用如下图。
parseLookupOverrideSubElements
解析bean中的lookup-method标签
这里要注意一下lookup-method标签会被封装到BeanDefinition的MethodOverrides属性中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 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); } } }
其他的parseReplacedMethodSubElements解析replaced-method标签也会被封装到BeanDefinition的MethodOverrides属性中
parseConstructorArgElements
解析bean中的constructor-arg标签,并将解析的数据封装到BeanDefinition的ConstructorArgumentValues属性中来
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 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); } } }
拿到 beanEle 节点的所有子节点,遍历解析所有是 constructor-arg 节点的子节点
constructor-arg 的使用如下所示,constructor-arg 节点类似于构造函数,bean 中必须要有相应的构造函数才可以使用,否则会报错。
1 2 3 4 <bean id ="userDao" class ="com.test.spring.dao.UserDao" > <constructor-arg index ="0" value ="Mysql" /> <constructor-arg index ="1" value ="select 1" /> </bean >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class UserDao { private String dialect; private String pingSql; public UserDao (String dialect, String pingSql) { this .dialect = dialect; this .pingSql = pingSql; } }
parseConstructorArgElement
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 public void parseConstructorArgElement (Element ele, BeanDefinition bd) { String indexAttr = ele.getAttribute(INDEX_ATTRIBUTE); String typeAttr = ele.getAttribute(TYPE_ATTRIBUTE); String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); if (StringUtils.hasLength(indexAttr)) { 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)); 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 { 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(); } } }
1.首先拿到基础属性 index、type、name 的属性值。
2.index不为空的处理:
2.1 首先解析 ele 节点的值,可以看代码块4里的图,每个 constructor-arg 节点必然有一个属性值,可能是通过 value 属性、ref 属性、list 属性等。
2.5 判断index是否重复指定,如果是则抛出异常;如果不重复,则将 index 和 valueHolder 以 key-value 形式添加至当前BeanDefinition 的 constructorArgumentValues 的 indexedArgumentValues 属性中(用于前面判断index是否重复指定)。
3.index为空的处理。基本与2相同,不在赘述。
parsePropertyValue
解析属性元素的值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 @Nullable public Object parsePropertyValue (Element ele, BeanDefinition bd, @Nullable String propertyName) { String elementName = (propertyName != null ? "<property> element for property '" + propertyName + "'" : "<constructor-arg> element" ); NodeList nl = ele.getChildNodes(); Element subElement = null ; for (int i = 0 ; i < nl.getLength(); i++) { Node node = nl.item(i); 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; } } } boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE); boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE); if ((hasRefAttribute && hasValueAttribute) || ((hasRefAttribute || hasValueAttribute) && subElement != null )) { error(elementName + " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element" , ele); } if (hasRefAttribute) { String refName = ele.getAttribute(REF_ATTRIBUTE); if (!StringUtils.hasText(refName)) { error(elementName + " contains empty 'ref' attribute" , ele); } RuntimeBeanReference ref = new RuntimeBeanReference (refName); ref.setSource(extractSource(ele)); return ref; } else if (hasValueAttribute) { TypedStringValue valueHolder = new TypedStringValue (ele.getAttribute(VALUE_ATTRIBUTE)); valueHolder.setSource(extractSource(ele)); return valueHolder; } else if (subElement != null ) { return parsePropertySubElement(subElement, bd); } else { error(elementName + " must specify a ref or value" , ele); return null ; } }
parsePropertySubElement
解析子元素属性的值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 @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)) { BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd); if (nestedBd != null ) { nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd); } return nestedBd; } else if (nodeNameEquals(ele, REF_ELEMENT)) { String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE); boolean toParent = false ; if (!StringUtils.hasLength(refName)) { 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; } else if (nodeNameEquals(ele, IDREF_ELEMENT)) { return parseIdRefElement(ele); } else if (nodeNameEquals(ele, VALUE_ELEMENT)) { return parseValueElement(ele, defaultValueType); } else if (nodeNameEquals(ele, NULL_ELEMENT)) { TypedStringValue nullHolder = new TypedStringValue (null ); nullHolder.setSource(extractSource(ele)); return nullHolder; } else if (nodeNameEquals(ele, ARRAY_ELEMENT)) { return parseArrayElement(ele, bd); } else if (nodeNameEquals(ele, LIST_ELEMENT)) { return parseListElement(ele, bd); } else if (nodeNameEquals(ele, SET_ELEMENT)) { return parseSetElement(ele, bd); } else if (nodeNameEquals(ele, MAP_ELEMENT)) { return parseMapElement(ele, bd); } else if (nodeNameEquals(ele, PROPS_ELEMENT)) { return parsePropsElement(ele); } else { error("Unknown property sub-element: [" + ele.getNodeName() + "]" , ele); return null ; } }
parseValueElement
解析Value的值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public Object parseValueElement (Element ele, @Nullable String defaultTypeName) { String value = DomUtils.getTextValue(ele); String specifiedTypeName = ele.getAttribute(TYPE_ATTRIBUTE); String typeName = specifiedTypeName; if (!StringUtils.hasText(typeName)) { typeName = defaultTypeName; } try { TypedStringValue typedValue = buildTypedStringValue(value, typeName); typedValue.setSource(extractSource(ele)); typedValue.setSpecifiedTypeName(specifiedTypeName); return typedValue; } catch (ClassNotFoundException ex) { error("Type class [" + typeName + "] not found for <value> element" , ele, ex); return value; } }
buildTypedStringValue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 protected TypedStringValue buildTypedStringValue (String value, @Nullable String targetTypeName) throws ClassNotFoundException { ClassLoader classLoader = this .readerContext.getBeanClassLoader(); TypedStringValue typedValue; if (!StringUtils.hasText(targetTypeName)) { typedValue = new TypedStringValue (value); } else if (classLoader != null ) { Class<?> targetType = ClassUtils.forName(targetTypeName, classLoader); typedValue = new TypedStringValue (value, targetType); } else { typedValue = new TypedStringValue (value, targetTypeName); } return typedValue; }
parseSetElement
解析集合元素
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 public List<Object> parseListElement (Element collectionEle, @Nullable BeanDefinition bd) { String defaultElementType = collectionEle.getAttribute(VALUE_TYPE_ATTRIBUTE); NodeList nl = collectionEle.getChildNodes(); ManagedList<Object> target = new ManagedList <>(nl.getLength()); target.setSource(extractSource(collectionEle)); target.setElementTypeName(defaultElementType); target.setMergeEnabled(parseMergeAttribute(collectionEle)); parseCollectionElements(nl, target, bd, defaultElementType); return target; } protected void parseCollectionElements ( NodeList elementNodes, Collection<Object> target, @Nullable BeanDefinition bd, String defaultElementType) { for (int i = 0 ; i < elementNodes.getLength(); i++) { Node node = elementNodes.item(i); if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT)) { target.add(parsePropertySubElement((Element) node, bd, defaultElementType)); } } }
正常情况下,list 里面应该是 value节点(见下图),则会走到代码块8 解析出对应的value,然后结束。特殊情况下,可能 list 里面还是 list,则相当于递归在走到此方法。
parsePropertyElements
解析bean中的property标签,并封装到BeanDefinition的MutablePropertyValues属性中来
1 2 3 4 5 6 7 8 9 10 11 12 13 14 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); } } }
拿到 beanEle 节点的所有子节点,遍历解析所有是 property 节点的子节点,property 的使用如下图所示,property 节点类似于set方法,bean 中的属性必须要有 set 方法才可以使用,否则会报错。
1 2 3 4 5 6 7 8 9 10 <bean id ="userDao" class ="com.test.spring.dao.UserDao" > <property name ="dialect" value ="mysql" /> <property name ="pingSql" value ="select 1" /> <property name ="dbList" > <list > <value > db2</value > <value > oracle</value > </list > </property > </bean >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 public class UserDao { private String dialect; private String pingSql; private List<String> dbList; public String getDialect () { return dialect; } public void setDialect (String dialect) { this .dialect = dialect; } public String getPingSql () { return pingSql; } public void setPingSql (String pingSql) { this .pingSql = pingSql; } public List<String> getDbList () { return dbList; } public void setDbList (List<String> dbList) { this .dbList = dbList; } @Override public String toString () { return "UserDao{" + "dialect='" + dialect + '\'' + ", pingSql='" + pingSql + '\'' + '}' ; } }
parsePropertyElement
解析bean中的property标签
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 public void parsePropertyElement (Element ele, BeanDefinition bd) { 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(); } }
小结
这一部分是将默认标签解析成BeanDefinition的主要过程
获取元素的id属性设置给beanName属性
检查beanName是否存在
创建GenericBeanDefinition对象并初始化parentName,beanClass等信息
公共标签属性的解析,并把解析出来的属性设置到BeanDefinition对象中
解析lookup-method标签封装为LookupOverride添加到BeanDefinition的methodOverrides中
解析replaced-method标签封装为ReplaceOverride添加到BeanDefinition的methodOverrides中
解析constructor-arg标签封装为ConstructorArgumentValues添加到BeanDefinition的constructorArgumentValues中
解析property标签封装为PropertyValue添加到BeanDefinition的propertyValues中
decorateBeanDefinitionIfRequired
该方法功能不重要,设计模式重点看一下,装饰者设计模式,加上SPI设计思想
主要实现了命令标签的解析类似于 p:username=”Jack” p:password=”123” c:age=”12” c:sex=”1”标签的解析
decorateBeanDefinitionIfRequired
开始对<bean class=”xx” p:username=”yyy”/>标签的解析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 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) { finalDefinition = decorateIfRequired(node, finalDefinition, containingBd); } } return finalDefinition; }
核心方法是decorateIfRequired 方法使用了装饰者模式
decorateIfRequired
装饰者设计模式 实现了命名控制属性注入的
是spring的SPI机制,从spring.handlers获取对应的解析类进行操作 具体流程可以参考《命名空间解析》
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 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/schema/" )) { error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]" , node); } else { if (logger.isDebugEnabled()) { logger.debug("No Spring NamespaceHandler found for XML schema namespace [" + namespaceUri + "]" ); } } } return originalDef; }
decorate
来到SimplePropertyNamespaceHandler类的decorate方法,进行装饰元素的解析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 @Override public BeanDefinitionHolder decorate (Node node, BeanDefinitionHolder definition, ParserContext parserContext) { if (node instanceof Attr) { Attr attr = (Attr) node; String propertyName = parserContext.getDelegate().getLocalName(attr); String propertyValue = attr.getValue(); MutablePropertyValues pvs = definition.getBeanDefinition().getPropertyValues(); if (pvs.contains(propertyName)) { parserContext.getReaderContext().error("Property '" + propertyName + "' is already defined using " + "both <property> and inline syntax. Only one approach may be used per property." , attr); } if (propertyName.endsWith(REF_SUFFIX)) { propertyName = propertyName.substring(0 , propertyName.length() - REF_SUFFIX.length()); pvs.add(Conventions.attributeNameToPropertyName(propertyName), new RuntimeBeanReference (propertyValue)); } else { pvs.add(Conventions.attributeNameToPropertyName(propertyName), propertyValue); } } return definition; }
该方法是对解析bean的装饰对<bean class=”xx” p:username=”yyy”/>标签进行解析
小结 解析流程如下
获取装饰元素的名称 例如p:username 获取对应的名称 username
获取对应的value
检查属性名称是否有-ref,如果有说明是引用的其他bean元素 类似于<property name=”xx” ref=”yy”/>
首先去掉**-ref**字符
将其value转换成RuntimeBeanReference引用类型加入到MutablePropertyValues
如果不包含**-ref**,将属性的名称和值加入MutablePropertyValues
注册BeanDefinition registerBeanDefinition
注册BeanDefinition
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 public static void registerBeanDefinition ( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { String beanName = definitionHolder.getBeanName(); registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); String[] aliases = definitionHolder.getAliases(); if (aliases != null ) { for (String alias : aliases) { registry.registerAlias(beanName, alias); } } }