3.1bean标签解析及注册
默认标签解析是在parseDefaultElement中进行的。下面函数功能一目了然,分别对四种标签(import,alias,bean,beans)做不同处理。
DefaultBeanDefinitionDocumentReader private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { importBeanDefinitionResource(ele); } else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { processAliasRegistration(ele); } else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { processBeanDefinition(ele, delegate); } else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // recurse doRegisterBeanDefinitions(ele); } }
在四种标签的解析中,bean标签的解析最为复杂也最重要。所以我们从此标签开始分析,如果理解了此标签的解析过程,其他三种也就迎刃而解了。
解析bean标签
DefaultBeanDefinitionDocumentReader protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { //委托BeanDefinitionDelegate类的parseBeanDefinitionElement方法进行元素解析, //返回BeanDefinitionHolder类型的实例bdholder, //经过这个方法后,bdholder已经包含了配置文件中的配置的各种属性(class、name、id、alias......) 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)); } }
以上代码大致逻辑:
1)首先委托BeanDefinitionDelegate类的parseBeanDefinitionElement方法对bean标签解析,返回BeanDefinitionHolder类型的实例bdholder(BeanDefinitionHolder有三个属性:BeanDefinition、beanName、aliases),经过这个方法后,bdholder已经包含了bean标签中的配置的各种属性(class、name、id、alias......)
2)当返回的bdholder不为空的情况下并且bean标签下有自定义标签,还需要对自定义标签解析。
3)解析完成后,需要对解析后的bdholder进行注册。委托给BeanDefinitionReaderUtils的regiestBeanDefinition方法(实际执行注册的是BeanDefinitionRegistry的实现类DefaultListable-BeanFactory)
4)最后发出响应事件,通知相关监听器,这个bean已经加载完毕。
下面是时序图:

3.1Bean标签的解析及注册
3.1.1解析BeanDefinition(将Xml的Bean标签Element转换为BeanDefinition的实现类GenericBeanDefinition)
BeanDefinitionParserDelegate.Java @Nullable public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) { return parseBeanDefinitionElement(ele, null); } @Nullable public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) { //加载id与name属性 String id = ele.getAttribute(ID_ATTRIBUTE); String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); //将name属性用,;分割放到集合中 List<String> aliases = new ArrayList<>(); if (StringUtils.hasLength(nameAttr)) { String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS); aliases.addAll(Arrays.asList(nameArr)); } //beanName为放入容器中的name //默认将id设置为beanname //如果id为空,将name属性集合中的第一个设置为beanname 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) { //如果id属性、name属性都为空 if (!StringUtils.hasText(beanName)) { try { //如果id属性、name属性都为空且为内部bean //自动生成beanname //生成的规则是: //1)如果有父类parentName,获取父类parentName+$child+#1...#2(#1,#2为递增) //2)如果没有parentName,获取工厂名factoryName+created+#1...#2 if (containingBean != null) { beanName = BeanDefinitionReaderUtils.generateBeanName( beanDefinition, this.readerContext.getRegistry(), true); } else { //如果id属性、name属性都为空、不是内部bean //自动生成beanname //生成的规则是: //1)如果有父类parentName,获取父类parentName+$child //2)如果没有parentName,获取工厂名factoryName+created beanName = this.readerContext.generateBeanName(beanDefinition); // Register an alias for the plain bean class name, if still possible, // if the generator returned the class name plus a suffix. // This is expected for Spring 1.2/2.0 backwards compatibility. String beanClassName = beanDefinition.getBeanClassName(); if (beanClassName != null && beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() && !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) { aliases.add(beanClassName); } } if (logger.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; }
以上代码完成的工作:
1)提取元素中的id和name属性
2)进一步解析其他所有属性并统一封装到GenericBeanDefinition类型的实例中
3)如果监测到bean没有指定beanName,那么使用默认规则为此bean生成beanName
4)将获取到的信息封装到BeanDefinitionHolder实例中
beanName生成规则:
1)将id设置为beanName
2)id为空,将name设置为beanName,name可以有多个,用 ,; 分割
3)如果id,name都为空,自动生成beanName
3.1)如果是内部bean,(初始化的时候是内部bean)
//生成的规则是:
//1)如果有父类parentName,获取父类parentName+$child+#1...#2(#1,#2为递增)
//2)如果没有parentName,获取工厂名factoryName+created+#1...#2
3.2)如果是不是内部bean(区别是没有递增的#1...#2)
//生成的规则是:
//1)如果有父类parentName,获取父类parentName+$child
//2)如果没有parentName,获取工厂名factoryName+created
接下来我们看步骤2中对标签其他属性的解析过程
BeanDefinitionParserDelegate.Java public AbstractBeanDefinition parseBeanDefinitionElement( Element ele, String beanName, @Nullable BeanDefinition containingBean) { this.parseState.push(new BeanEntry(beanName)); //解析class属性 String className = null; if (ele.hasAttribute(CLASS_ATTRIBUTE)) { className = ele.getAttribute(CLASS_ATTRIBUTE).trim(); } //解析parent属性 String parent = null; if (ele.hasAttribute(PARENT_ATTRIBUTE)) { parent = ele.getAttribute(PARENT_ATTRIBUTE); } try { //创建用于承载属性的AbstractBeanDefinition类型的GenericBeanDefinition AbstractBeanDefinition bd = createBeanDefinition(className, parent); //硬编码解析默认bean的各种属性 //解析方式:获取ele的节点属性 parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT)); //以下都是解析bean的子属性 //解析元数据 //下面的所有属性的解析方式:获取ele节点的所有子节点childNode进行遍历,判断equals parseMetaElements(ele, bd); //解析lookup-method属性 parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); //解析replaced-method属性 parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); //解析构造函数 parseConstructorArgElements(ele, bd); //解析property子元素 parsePropertyElements(ele, bd); //解析qualifiter子元素 //Spring允许我们通过Qualifier指定注入Bean的名称,这样歧义就消除了 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.创建用于属性承载的BeanDefinition
BeanDefinition是一个接口,在Spring中存在三种实现:RootBeanDefinition、ChildBeanDefinition、GenericBeanDefinition,三个实现都集成了AbstractBean-Definition,其中,Bean是配置文件中<bean>元素标签在容器中的内部表现形式(就是把XML配置中的bean标签抽象成了BeanDefinition对象)。Bean标签与BeanDefinition对象的属性是一一对应的。
BeanDefinitionParserDelegate protected AbstractBeanDefinition createBeanDefinition(@Nullable String className, @Nullable String parentName) throws ClassNotFoundException { return BeanDefinitionReaderUtils.createBeanDefinition( parentName, className, this.readerContext.getBeanClassLoader()); } BeanDefinitionReaderUtils public static AbstractBeanDefinition createBeanDefinition( @Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException { GenericBeanDefinition bd = new GenericBeanDefinition(); //parentName可能为空 bd.setParentName(parentName); if (className != null) { //如果classLoader不为空,则使用以传入的classLoader同一虚拟机加载类对象 //否则只记录className if (classLoader != null) { bd.setBeanClass(ClassUtils.forName(className, classLoader)); } else { bd.setBeanClassName(className); } } return bd; }
2.解析各种属性
示例:<bean id="" name="" scope="" lazy-init />
解析bean标签上的属性(scope、lazy-init、autowire.....)
BeanDefinitionParserDelegate public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName, @Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) { if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) { //解析singleton属性,但是这个版本已经移除 error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele); } else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) { //解析scope属性 bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE)); } else if (containingBean != null) { // Take default from containing bean in case of an inner bean definition. //在嵌入beanDefinition情况下且没有单独指定scope属性则使用父类默认的属性 //空和singleton都是单例 bd.setScope(containingBean.getScope()); } //解析abstract属性 if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) { bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE))); } //解析lazy-init属性 String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE); if (isDefaultValue(lazyInit)) { lazyInit = this.defaults.getLazyInit(); } //若没有设置或者设置成其他字符都会被设置为false bd.setLazyInit(TRUE_VALUE.equals(lazyInit)); //解析autoWire属性 String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE); bd.setAutowireMode(getAutowireMode(autowire)); //解析depends-on属性 //用来表示一个bean的实例化依靠另一个bean先实例化,对应bean属性depend-on if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) { String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE); bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS)); } //解析autowire-candidate属性 //autowire-candidate属性设置为false,这样容器在查找自动装配时,将不考虑该bean。 //即它不会被考虑作为其他bean自动装配的候选者,但是该bean本身还是可以使用自动装配来注入其他bean String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE); if (isDefaultValue(autowireCandidate)) { String candidatePattern = this.defaults.getAutowireCandidates(); if (candidatePattern != null) { String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern); bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName)); } } else { bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate)); } //解析primary属性 //自动装配是当出现多个候选者时,将作为首选者,对应bean属性primary if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) { bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE))); } //解析init-method属性 //初始化方法 if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) { String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE); bd.setInitMethodName(initMethodName); } else if (this.defaults.getInitMethod() != null) { bd.setInitMethodName(this.defaults.getInitMethod()); bd.setEnforceInitMethod(false); } //解析destroy-method属性 //销毁方法 if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) { String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE); bd.setDestroyMethodName(destroyMethodName); } else if (this.defaults.getDestroyMethod() != null) { bd.setDestroyMethodName(this.defaults.getDestroyMethod()); bd.setEnforceDestroyMethod(false); } //解析factory-method属性 //用于实例化工厂类方法 if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) { bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE)); } //解析factory-bean属性 //用于调用工厂类 if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) { bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE)); } return bd; }
需要注意的是:
scope属性没有指定、scope属性指定singleton,都为单例,也就是说默认是单例。
autowire-candidate属性:默认true。设置为false时,容器在查找自动装配时,将不考虑此bean,即它不会被考虑作为其他bean自动装配的候选者,但是bean本身还是可以使用指定装配来注入其他bean。
primary属性:自动装配出现多个候选者的时候,将作为首选者。
depends-on属性:用来表示一个bean实例化依靠另一个bean先实例化。
factory-bean属性:用于工厂类的类。
factory-method属性:用于调用工厂类的实例化方法。
3.解析子元素meta
示例:
<bean id="myTestBean" class="bean.MyTestBean">
<meta key="testStr" value="aaabb" />
</bean>
meta是一个额外的声明,当需要使用里面的信息的时候可以通过BeanDefinition的getAttribute(key)方法进行获取。
BeanDefinitionParserDelegate public void parseMetaElements(Element ele, BeanMetadataAttributeAccessor attributeAccessor) { //获取当前节点的所有子元素 NodeList nl = ele.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); //提取meta if (isCandidateElement(node) && nodeNameEquals(node, META_ELEMENT)) { Element metaElement = (Element) node; String key = metaElement.getAttribute(KEY_ATTRIBUTE); String value = metaElement.getAttribute(VALUE_ATTRIBUTE); //使用key、value构造beanMetadataAttribute BeanMetadataAttribute attribute = new BeanMetadataAttribute(key, value); attribute.setSource(extractSource(metaElement)); //bd记录信息 attributeAccessor.addMetadataAttribute(attribute); } } }
4.解析子元素lookup-method
lookup-method获取器注入。
获取器注入:是一种特殊的方法注入。它是把一个方法声明为返回某种类型的bean,但实际要返回的bean是在配置文件里面配置的。此方法可用在设计有些可插拔功能上,解除程序依赖。
示例:
//创建一个父类 public class User{ public void showMe(){ System.out.println("i am user"); } } //创建其子类并覆盖showMe()方法 public class Teacher extend User{ public void showMe(){ System.out.println("i am teacher"); } } //创建调用方法 public abstract class GetBeanTest{ public abstract User getBean(){}; public void showMe(){ this.getBean.showMe(); } } //创建测试方法 public class Main{ public static void main(String[] args){ ApplicationContext bf = new ClassPathXmlApplicationContext("test/lookup/lookupTest.xml"); GetBeanTest test = (GetBeanTest)bf.getBean("getBeanTest"); test.show(); } } //xml配置 <xml> <beans> <bean id="getBeanTest" class="GetBeanTest"> //name为调用方法中的getBean属性 <lookup-method name="getBean" bean="teacher" /> //可以插拔替换功能,解除程序依赖。 //<lookup-method name="geBean" bean="userExt" /> </bean> <bean id="teacher" class="Teacher" /> <bean id="任何User的实现类 userExt" class="" /> </beans> </xml> BeanDefenitionParserDelegate public void parseLookupOverrideSubElements(Element beanEle, MethodOverrides overrides) { NodeList nl = beanEle.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); //仅当在Spring默认bean的子元素下且为<lookup-method />时有效 if (isCandidateElement(node) && nodeNameEquals(node, LOOKUP_METHOD_ELEMENT)) { Element ele = (Element) node; //获取要修饰的方法 String methodName = ele.getAttribute(NAME_ATTRIBUTE); //获取配置返回的bean String beanRef = ele.getAttribute(BEAN_ELEMENT); LookupOverride override = new LookupOverride(methodName, beanRef); override.setSource(extractSource(ele)); overrides.addOverride(override); } } }
5.解析子元素replaced-method
replace的场景:方法替换。与lookup不同的是,repalced-method不但可以动态替换返回实体bean,而且还能动态地更改原有方法的逻辑。
replace的用法:
//在changeMe中完成某个业务逻辑 public class TestChangeMethod{ public void changeMe(){ System.out.println("changeMe"); } } //运营一段时间后,需要改变原有业务逻辑 public class TestMethodReplacer implement MethodReplacer{ @Override public Object reimplement(Object object,Method method,Object[] args)throws Throwable{ System.out.println("我替换了原有的方法"); return null; } } //XML配置 <XML> <beans> <bean id="testChangeMethod" class="TestChangeMethod"> //name为方法changeMe() <replaced-method name="changeMe" replacer="replacer" /> </bean> <bean id="replacer" class="TestMethodReplacer"></bean> </beans> </XML> BeanDefinitionParserDelagate public void parseReplacedMethodSubElements(Element beanEle, MethodOverrides overrides) { NodeList nl = beanEle.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); //仅当在Spring默认bean的子元素下且为<replace-method时有效 if (isCandidateElement(node) && nodeNameEquals(node, REPLACED_METHOD_ELEMENT)) { Element replacedMethodEle = (Element) node; //提取要替换的方法 String name = replacedMethodEle.getAttribute(NAME_ATTRIBUTE); //提取对应的新的替换方法 String callback = replacedMethodEle.getAttribute(REPLACER_ATTRIBUTE); ReplaceOverride replaceOverride = new ReplaceOverride(name, callback); // Look for arg-type match elements. List<Element> argTypeEles = DomUtils.getChildElementsByTagName(replacedMethodEle, ARG_TYPE_ELEMENT); for (Element argTypeEle : argTypeEles) { //记录参数 String match = argTypeEle.getAttribute(ARG_TYPE_MATCH_ATTRIBUTE); match = (StringUtils.hasText(match) ? match : DomUtils.getTextValue(argTypeEle)); if (StringUtils.hasText(match)) { replaceOverride.addTypeIdentifier(match); } } replaceOverride.setSource(extractSource(replacedMethodEle)); overrides.addOverride(replaceOverride); } } }
6.解析子元素constructor-arg
constructor-arg示例:
<bean id="helloBean" class="HelloBean"> <contructor-arg index="0"> <value>Shing</value> </contructor-arg> <contructor-arg index="1"> <value>你好</value> </contructor-arg> </bean> BeanDefinitionParserDelegate 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); } } } BeanDefinitionParserDelegate 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); if (index < 0) { error("'index' cannot be lower than 0", ele); } else { try { this.parseState.push(new ConstructorArgumentEntry(index)); //解析ele对应的属性元素 Object value = parsePropertyValue(ele, bd, null); ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value); if (StringUtils.hasLength(typeAttr)) { valueHolder.setType(typeAttr); } if (StringUtils.hasLength(nameAttr)) { valueHolder.setName(nameAttr); } valueHolder.setSource(extractSource(ele)); //不允许重复指定相同参数 if (bd.getConstructorArgumentValues().hasIndexedArgumentValue(index)) { error("Ambiguous constructor-arg entries for index " + index, ele); } else { bd.getConstructorArgumentValues().addIndexedArgumentValue(index, valueHolder); } } finally { this.parseState.pop(); } } } catch (NumberFormatException ex) { error("Attribute 'index' of tag 'constructor-arg' must be an integer", ele); } } else { //没有index属性则忽略属性 try { this.parseState.push(new ConstructorArgumentEntry()); Object value = parsePropertyValue(ele, bd, null); ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value); if (StringUtils.hasLength(typeAttr)) { valueHolder.setType(typeAttr); } if (StringUtils.hasLength(nameAttr)) { valueHolder.setName(nameAttr); } valueHolder.setSource(extractSource(ele)); bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder); } finally { this.parseState.pop(); } } }
上面的代码的逻辑:
- 如果配置中指定了Index属性
1.解析contructor-arg的子元素
2.使用ContructorArgumentValues.ValueHolder类型来封装解析出来的元素
3.将type、name、index属性封装到ContructorArgumentValues.ValueHolder类型 中,并添加到当前Beandefinition的contructorArgumentValues的indexed- ArgumentValue属性中
- 如果没有指定index属性
1.解析contructor-arg的子元素
2.使用ContructorArgumentValues.ValueHolder类型来封装解析出来的元素
3.将type、name、index属性封装到ContructorArgumentValues.ValueHolder类型 中,并添加到当前Beandefinition的contructorArgumentValues的indexed- ArgumentValue属性中
对于是否指定Index属性,Spring的处理流程是一样的,区别在于属性信息保存的位置。
接下里进一步了解解析构造函数配置中子元素的过程parsePropertyValue
//BeanDefinitionParserDelegate public Object parsePropertyValue(Element ele, BeanDefinition bd, @Nullable String propertyName) { String elementName = (propertyName != null ? "<property> element for property '" + propertyName + "'" : "<constructor-arg> element"); // Should only have one child element: ref, value, list, etc. //一个属性只能对应一种类型ref, value, list, etc. NodeList nl = ele.getChildNodes(); Element subElement = null; for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); //对应description或者meta不处理 if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) && !nodeNameEquals(node, META_ELEMENT)) { // Child element is what we're looking for. if (subElement != null) { error(elementName + " must not contain more than one sub-element", ele); } else { subElement = (Element) node; } } } //解析constructor-arg上的ref属性 boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE); //解析constructor-arg上的value属性 boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE); if ((hasRefAttribute && hasValueAttribute) || ((hasRefAttribute || hasValueAttribute) && subElement != null)) { /** * 在constructor-arg上不存在的情况: * 1.同时具有ref、value属性 * 2.存在ref属性或者value属性且又有子元素 */ error(elementName + " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele); } if (hasRefAttribute) { //Ref属性的处理,使用RuntimeBeanReference封装对应的ref名称 String refName = ele.getAttribute(REF_ATTRIBUTE); if (!StringUtils.hasText(refName)) { error(elementName + " contains empty 'ref' attribute", ele); } RuntimeBeanReference ref = new RuntimeBeanReference(refName); ref.setSource(extractSource(ele)); return ref; } else if (hasValueAttribute) { //value属性的处理,使用TypedStringValue封装 TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE)); valueHolder.setSource(extractSource(ele)); return valueHolder; } else if (subElement != null) { //解析构造函数中嵌入子元素 return parsePropertySubElement(subElement, bd); } else { // Neither child element nor "ref" or "value" attribute found. //既没有ref也没有value也没有子元素,Spring蒙圈了 error(elementName + " must specify a ref or value", ele); return null; } }
上面代码的逻辑:
1)略过description或者meta。
2)提取constructor-arg上的ref、value属性,以便根据规则验证正确性,验证其不规范的以下两种情况
- 同时既有ref属性又有value属性
- 存在ref属性或者value属性且又有子元素
3)ref属性的处理。<constructor-arg ref="xxx" />
4)value属性的处理。<constructor-arg value="xxx" />
5)子元素的处理。例如
<constructor-arg><map><entry key="key" value="value" /></map></constructor-arg>ref属性、value属性、constructor子元素,从左到右权重递减。
解析constructor-arg的子元素parsePropertySubElement
BeanDefinitionParserDelegate public Object parsePropertySubElement(Element ele, @Nullable BeanDefinition bd, @Nullable String defaultValueType) { if (!isDefaultNamespace(ele)) { return parseNestedCustomElement(ele, bd); } //解析bean子元素 else if (nodeNameEquals(ele, BEAN_ELEMENT)) { //这里存在嵌套的情况,如果bean-a依赖了bean-b,那么先注册bean-b后在注册bean-a 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; } //解析value子元素 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)) { // 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; } 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; } }
这里的解析不看了,感觉解析逻辑都差不多
7.解析子元素property
property示例:
<bean id="testproperty" class="TestProperty"> <property name="testStr" value="aaa" /> </bean> <bean id="testproperty" class="TestProperty"> <property name="p"> <list> <value>1</value> <value>2</value> </list> </property> </bean>
解析过程
public void parsePropertyElements(Element beanEle, BeanDefinition bd) { NodeList nl = beanEle.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) { parsePropertyElement((Element) node, bd); } } } /** * Parse a property element. * <bean id="test" class="test.TestClass"> * <property name="p" value="aaa"></property> * </bean> * 或者 * <bean id="test"> * <property name="p"> * <list> * <value>aa</value> * <value><bb/value> * </list> * </property> * </bean> */ public void parsePropertyElement(Element ele, BeanDefinition bd) { //获取配置元素中的name属性 String propertyName = ele.getAttribute(NAME_ATTRIBUTE); if (!StringUtils.hasLength(propertyName)) { error("Tag 'property' must have a 'name' attribute", ele); return; } this.parseState.push(new PropertyEntry(propertyName)); try { //不允许多次对同一属性配置 if (bd.getPropertyValues().contains(propertyName)) { error("Multiple 'property' definitions for property '" + propertyName + "'", ele); return; } Object val = parsePropertyValue(ele, bd, propertyName); PropertyValue pv = new PropertyValue(propertyName, val); parseMetaElements(ele, pv); pv.setSource(extractSource(ele)); bd.getPropertyValues().addPropertyValue(pv); } finally { this.parseState.pop(); } }
8.解析子元素qualifier
qualifier:Spring允许我们通过Qualifier属性指定注入Bean的名称,这样歧义就消除了。bean的名称,不在是id、name、自动生成(自动生成规则上面有写)
示例:
<bean id="testQualifier" class="TestQualifier"> //value属性就是指定的bean的名称,不在是id、name、自动生成 <qualifier type="org.Springframework.beans.factory.annotation.Qualifie" value="qf" /> </bean>
本来打算在接下来的逻辑放在这里的,但是太长了,新开一个文档。

浙公网安备 33010602011771号