Spring源码解析笔记2——默认标签的解析
2018-01-10 16:17
696 查看
继续前面的this.parseDefaultElement(ele, delegate)讨论。
重点研究如何处理bean标签,import和alias和beans放在最后说明,继续this.processBeanDefinition(ele, delegate)方法。
1.根据以上步骤分析,首先分析parseBeanDefinitionElement(Element ele):
parseBeanDefinitionElement(Element ele)方法:
上一步的核心方法:parseBeanDefinitionElement(ele, beanName1, containingBean),将其他所有属性统一封装至GenericBeanDefinition类型中。
this.createBeanDefinition(className, ex)是生成GenericBeanDefinition类型的实例。
关于GenericBeanDefinition
BeanDefinition是配置文件bean>元素标签在容器中的内部表现形式。bean>元素标签拥有的class,scope,lazy-init等配置属性对应BeanDefinition中的beanClass,scope,lazyInit属性。
在bean>标签中,父bean>用RootBeanDefinition表示,子bean>用ChildBeanDefinition表示,没有父bean>的bean>就使用RootBeanDefinition表示。AbstractBeanDefinition对两者共同的类信息进行了抽象。
ChildBeanDefinition和RootBeanDefinition在spring2.5以后就被GenericBeanDefinition代替了,GenericBeanDefinition相比于RootBeanDefinition和ChildBeanDefinition在定义的时候就必须硬编码,GenericBeanDefinition的优点可以动态的为GenericBeanDefinition设置parent。
解析各种属性this.parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
this.parseMetaElements(ele, bd); 解析子元素meta,元数据属性。
this.parseLookupOverrideSubElements(ele, bd.getMethodOverrides());解析子元素lookup-method ,
首先解释一下lookup-method这个子元素的作用,通常被称为获取器注入。
this.parseLookupOverrideSubElements(ele, bd.getMethodOverrides());方法源码
解析子元素replaced-method
解释replaced-method的作用
this.parseReplacedMethodSubElements(ele, bd.getMethodOverrides());方法源码
解析子元素constructor-arg
this.parseConstructorArgElements(ele, bd);的源码:
关于 this.parseConstructorArgElements(ele, bd);的源码中的parsePropertyValue(Element ele, BeanDefinition bd, String propertyName)方法源码:
子元素的处理 this.parsePropertySubElement(subElement, bd)源码根据源码可以看到constructor-arg支持的子元素
解析子元素property,property的作用如下。
解析property的方法this.parsePropertyElements(ele, bd)源码为:
解析子元素qualifier,该元素的作用是,大多数时候都用注解的方式。解析的过程与前面相似。
Qualifier的配置文件使用方法。
2.根据文章开头processBeanDefinition方法下面的bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder)的decorateBeanDefinitionIfRequired方法:该方法是用来解析默认标签中的自定义标签。
3.根据文章开头processBeanDefinition方法下面的BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry())追踪:
4.最开始只解析了bean标签,此处补充alias和import和beans标签。
alias标签的解析。
首先解释一下alias的作用,在对bean进行定义时,除了使用id属性来指定名称以外,为了提供多个名称,可以使用alias标签来指定。
查看this.processAliasRegistration(ele)源码
impot标签的解析
首先解释一下import标签的作用,将配置文件分块,利用import导入多个配置文件。
this.importBeanDefinitionResource(ele)的源码:
嵌入式beans标签的解析
xbeans标签与单独的配置文件并没有太大差别,是递归调用bean的解析过程。
//分别对4种不同的标签(import,alias,bean,beans)做了不同的处理。 private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { if(delegate.nodeNameEquals(ele, "import")) { this.importBeanDefinitionResource(ele); } else if(delegate.nodeNameEquals(ele, "alias")) { this.processAliasRegistration(ele); } else if(delegate.nodeNameEquals(ele, "bean")) { this.processBeanDefinition(ele, delegate); } else if(delegate.nodeNameEquals(ele, "beans")) { this.doRegisterBeanDefinitions(ele); } }
重点研究如何处理bean标签,import和alias和beans放在最后说明,继续this.processBeanDefinition(ele, delegate)方法。
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { //返回的bdHolder实例已经包含配置文件中的各种属性了,class,name等。 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if(bdHolder != null) { //对自定义标签进行解析。 bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { //注册解析的BeanDefinition BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException var5) { this.getReaderContext().error("Failed to register bean definition with name \'" + bdHolder.getBeanName() + "\'", ele, var5); } //通知监听器,这个bean已经加载完了 this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } }
1.根据以上步骤分析,首先分析parseBeanDefinitionElement(Element ele):
parseBeanDefinitionElement(Element ele)方法:
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) { //提取元素中的id以及name。 String id = ele.getAttribute("id"); String nameAttr = ele.getAttribute("name"); ArrayList aliases = new ArrayList(); if(StringUtils.hasLength(nameAttr)) { String[] beanName = StringUtils.tokenizeToStringArray(nameAttr, ",; "); aliases.addAll(Arrays.asList(beanName)); } String beanName1 = id; if(!StringUtils.hasText(id) && !aliases.isEmpty()) { beanName1 = (String)aliases.remove(0); if(this.logger.isDebugEnabled()) { this.logger.debug("No XML \'id\' specified - using \'" + beanName1 + "\' as bean name and " + aliases + " as aliases"); } } if(containingBean == null) { this.checkNameUniqueness(beanName1, aliases, ele); } //核心方法,进一步解析其他所有属性并统一封装至GenericBeanDefinition类型的实例。 AbstractBeanDefinition beanDefinition = this.parseBeanDefinitionElement(ele, beanName1, containingBean); if(beanDefinition != null) { if(!StringUtils.hasText(beanName1)) { try { if(containingBean != null) { beanName1 = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, this.readerContext.getRegistry(), true); } else { beanName1 = this.readerContext.generateBeanName(beanDefinition); String aliasesArray = beanDefinition.getBeanClassName(); if(aliasesArray != null && beanName1.startsWith(aliasesArray) && beanName1.length() > aliasesArray.length() && !this.readerContext.getRegistry().isBeanNameInUse(aliasesArray)) { aliases.add(aliasesArray); } } if(this.logger.isDebugEnabled()) { this.logger.debug("Neither XML \'id\' nor \'name\' specified - using generated bean name [" + beanName1 + "]"); } } catch (Exception var9) { this.error(var9.getMessage(), ele); return null; } } String[] aliasesArray1 = StringUtils.toStringArray(aliases); //将结果封装到BeanDefinitionHolder类中。 return new BeanDefinitionHolder(beanDefinition, beanName1, aliasesArray1); } else { return null; } }
上一步的核心方法:parseBeanDefinitionElement(ele, beanName1, containingBean),将其他所有属性统一封装至GenericBeanDefinition类型中。
public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, BeanDefinition containingBean) { this.parseState.push(new BeanEntry(beanName)); String className = null; //解析class属性 if(ele.hasAttribute("class")) { className = ele.getAttribute("class").trim(); } try { String ex = null; //解析parent属性 if(ele.hasAttribute("parent")) { ex = ele.getAttribute("parent"); } //核心方法1,生成GenericBeanDefinition,要解析属性,就必须先要创建用于承载属性的实例。 AbstractBeanDefinition bd = this.createBeanDefinition(className, ex); //硬编码解析默认的bean的各种属性。 this.parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); bd.setDescription(DomUtils.getChildElementValueByTagName(ele, "description")); //解析元数据 this.parseMetaElements(ele, bd); //解析lookup-method属性 this.parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); //解析replaced-method属性。 this.parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); //解析构造函数参数 < 1d25c span class="hljs-keyword">this.parseConstructorArgElements(ele, bd); //解析property子元素 this.parsePropertyElements(ele, bd); //解析qualifier子元素 this.parseQualifierElements(ele, bd); bd.setResource(this.readerContext.getResource()); bd.setSource(this.extractSource(ele)); AbstractBeanDefinition var7 = bd; return var7; } catch (ClassNotFoundException var13) { this.error("Bean class [" + className + "] not found", ele, var13); } catch (NoClassDefFoundError var14) { this.error("Class that bean class [" + className + "] depends on not found", ele, var14); } catch (Throwable var15) { this.error("Unexpected failure during bean definition parsing", ele, var15); } finally { this.parseState.pop(); } return null; }
this.createBeanDefinition(className, ex)是生成GenericBeanDefinition类型的实例。
关于GenericBeanDefinition
BeanDefinition是配置文件bean>元素标签在容器中的内部表现形式。bean>元素标签拥有的class,scope,lazy-init等配置属性对应BeanDefinition中的beanClass,scope,lazyInit属性。
在bean>标签中,父bean>用RootBeanDefinition表示,子bean>用ChildBeanDefinition表示,没有父bean>的bean>就使用RootBeanDefinition表示。AbstractBeanDefinition对两者共同的类信息进行了抽象。
ChildBeanDefinition和RootBeanDefinition在spring2.5以后就被GenericBeanDefinition代替了,GenericBeanDefinition相比于RootBeanDefinition和ChildBeanDefinition在定义的时候就必须硬编码,GenericBeanDefinition的优点可以动态的为GenericBeanDefinition设置parent。
//父bean的实例: <bean id="abstractServiceThread" class="com.project.schedual.ServiceThread" abstract="true"> <property name="baseDao" ref="baseDAO"></property> </bean> //子bean的实例 <bean id="docReceiveFlowThread" parent="abstractServiceThread"> <property name="svc" ref="docReceiveFlowService"></property> </bean> . //createBeanDefinition源码: public static AbstractBeanDefinition createBeanDefinition(String parentName, String className, 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; }
解析各种属性this.parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName, BeanDefinition containingBean, AbstractBeanDefinition bd) { if(ele.hasAttribute("singleton")) { //scope与singleton两个属性只能指定其一,不能同时出现,否则报异常。 this.error("Old 1.x \'singleton\' attribute in use - upgrade to \'scope\' declaration", ele); } else if(ele.hasAttribute("scope")) { bd.setScope(ele.getAttribute("scope")); } else if(containingBean != null) { //在嵌入beanDifinition的情况下没有单独指定scope属性则使用父类默认的属性。 bd.setScope(containingBean.getScope()); } if(ele.hasAttribute("abstract")) { bd.setAbstract("true".equals(ele.getAttribute("abstract"))); } //解析lazy-init属性 String lazyInit = ele.getAttribute("lazy-init"); if("default".equals(lazyInit)) { lazyInit = this.defaults.getLazyInit(); } //如果没有设置或者设置为其他字符都会被设置成false bd.setLazyInit("true".equals(lazyInit)); //解析autowire属性 String autowire = ele.getAttribute("autowire"); bd.setAutowireMode(this.getAutowireMode(autowire)); //解析dependency-check属性 String dependencyCheck = ele.getAttribute("dependency-check"); bd.setDependencyCheck(this.getDependencyCheck(dependencyCheck)); String autowireCandidate; //解析depends-on属性 if(ele.hasAttribute("depends-on")) { autowireCandidate = ele.getAttribute("depends-on"); bd.setDependsOn(StringUtils.tokenizeToStringArray(autowireCandidate, ",; ")); } //解析autowire-candidate属性 autowireCandidate = ele.getAttribute("autowire-candidate"); String destroyMethodName; if(!"".equals(autowireCandidate) && !"default".equals(autowireCandidate)) { bd.setAutowireCandidate("true".equals(autowireCandidate)); } else { destroyMethodName = this.defaults.getAutowireCandidates(); if(destroyMethodName != null) { String[] patterns = StringUtils.commaDelimitedListToStringArray(destroyMethodName); bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName)); } } //解析primary属性 if(ele.hasAttribute("primary")) { bd.setPrimary("true".equals(ele.getAttribute("primary"))); } //解析init-method属性 if(ele.hasAttribute("init-method")) { destroyMethodName = ele.getAttribute("init-method"); if(!"".equals(destroyMethodName)) { bd.setInitMethodName(destroyMethodName); } } else if(this.defaults.getInitMethod() != null) { bd.setInitMethodName(this.defaults.getInitMethod()); bd.setEnforceInitMethod(false); } //解析destroy-method属性 if(ele.hasAttribute("destroy-method")) { destroyMethodName = ele.getAttribute("destroy-method"); bd.setDestroyMethodName(destroyMethodName); } else if(this.defaults.getDestroyMethod() != null) { bd.setDestroyMethodName(this.defaults.getDestroyMethod()); bd.setEnforceDestroyMethod(false); } //解析factory-method属性 if(ele.hasAttribute("factory-method")) { bd.setFactoryMethodName(ele.getAttribute("factory-method")); } //解析factory-bean属性 if(ele.hasAttribute("factory-bean")) { bd.setFactoryBeanName(ele.getAttribute("factory-bean")); } return bd; }
this.parseMetaElements(ele, bd); 解析子元素meta,元数据属性。
//meta标签使用举例 <bean id="myTestBean" class="bean.MyTestBean"> <meta key="testStr" value="aaaaa"> </bean> public void parseMetaElements(Element ele, BeanMetadataAttributeAccessor attributeAccessor) { NodeList nl = ele.getChildNodes(); for(int i = 0; i < nl.getLength(); ++i) { Node node = nl.item(i); if(this.isCandidateElement(node) && this.nodeNameEquals(node, "meta")) { Element metaElement = (Element)node; String key = metaElement.getAttribute("key"); String value = metaElement.getAttribute("value"); BeanMetadataAttribute attribute = new BeanMetadataAttribute(key, value); attribute.setSource(this.extractSource(metaElement)); attributeAccessor.addMetadataAttribute(attribute); } } }
this.parseLookupOverrideSubElements(ele, bd.getMethodOverrides());解析子元素lookup-method ,
首先解释一下lookup-method这个子元素的作用,通常被称为获取器注入。
// 定义一个水果类 public class Fruit { public Fruit() { System.out.println("I got Fruit"); } } // 苹果 public class Apple extends Fruit { public Apple() { System.out.println("I got a fresh apple"); } } // 香蕉 public class Bananer extends Fruit { public Bananer () { System.out.println("I got a fresh bananer"); } } //水果盘,可以拿到水果 public abstract class FruitPlate{ // 抽象方法获取新鲜水果 protected abstract Fruit getFruit(); } <bean id="fruitPlate1" class="cn.com.willchen.test.di.FruitPlate"> <lookup-method name="getFruit" bean="apple"/> </bean> <bean id="fruitPlate2" class="cn.com.willchen.test.di.FruitPlate"> <lookup-method name="getFruit" bean="bananer"/> </bean> public static void main(String[] args) { ApplicationContext app = new >ClassPathXmlApplicationContext("classpath:resource/applicationContext.xml"); FruitPlate fp1= (FruitPlate)app.getBean("fruitPlate1"); FruitPlate fp2 = (FruitPlate)app.getBean("fruitPlate2"); fp1.getFruit(); fp2.getFruit(); }
this.parseLookupOverrideSubElements(ele, bd.getMethodOverrides());方法源码
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(this.isCandidateElement(node) && this.nodeNameEquals(node, "lookup-method")) { Element ele = (Element)node; String methodName = ele.getAttribute("name"); String beanRef = ele.getAttribute("bean"); LookupOverride override = new LookupOverride(methodName, beanRef); override.setSource(this.extractSource(ele)); overrides.addOverride(override); } } }
解析子元素replaced-method
解释replaced-method的作用
public class TestChangMethod{ public void changMe(){ } } public class TestMethodReplacer implements MethodReplacer{ @Override public Object reimplements(Object obj,Method method,Object[] args) throws Throwable{ System.out.println("我替换了原有的方法"); return null; } }
//配置文件 <bean id="testChangeMethod" class="com.demo3.TestChangeMethod"> <replaced-method name="changeMe" replacer="replacer"/> </bean> <bean id="replacer" class="com.demo3.TestMethodReplacer"></bean>
//测试 public static void main(String[] args){ ApplicationContext bf = new ClassPathXmlApplicationContext("springContext.xml"); TestChangeMethod test = (TestChangeMethod )bf.getBean("testChangeMethod"); }
this.parseReplacedMethodSubElements(ele, bd.getMethodOverrides());方法源码
public void parseReplacedMethodSubElements(Element beanEle, MethodOverrides overrides) { NodeList nl = beanEle.getChildNodes(); for(int i = 0; i < nl.getLength(); ++i) { Node node = nl.item(i); if(this.isCandidateElement(node) && this.nodeNameEquals(node, "replaced-method")) { Element replacedMethodEle = (Element)node; String name = replacedMethodEle.getAttribute("name"); String callback = replacedMethodEle.getAttribute("replacer"); ReplaceOverride replaceOverride = new ReplaceOverride(name, callback); List argTypeEles = DomUtils.getChildElementsByTagName(replacedMethodEle, "arg-type"); Iterator var11 = argTypeEles.iterator(); while(var11.hasNext()) { Element argTypeEle = (Element)var11.next(); String match = argTypeEle.getAttribute("match"); match = StringUtils.hasText(match)?match:DomUtils.getTextValue(argTypeEle); if(StringUtils.hasText(match)) { replaceOverride.addTypeIdentifier(match); } } replaceOverride.setSource(this.extractSource(replacedMethodEle)); overrides.addOverride(replaceOverride); } } }
解析子元素constructor-arg
...... <beans> <!-- 默认的情况是按照参数的顺序注入,当指定index索引后就可以改变注入参数的顺序 --> <bean id="helloBean" class="com.HelloBean"> <constructor-arg index="0"> <value>张三</value> </constructor-arg> <constructor-arg index="1"> <value>李四</value> </constructor-arg> </bean> ...... </beans> <!--上面的配置实现的功能就是对HelloBean自动寻找对应的构造函数,并在初始化的时候设置参数传进去-->
this.parseConstructorArgElements(ele, bd);的源码:
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(this.isCandidateElement(node) && this.nodeNameEquals(node, "constructor-arg")) { //解析constructor-arg this.parseConstructorArgElement((Element)node, bd); } } } //this.parseConstructorArgElement((Element)node, bd);源码 public void parseConstructorArgElement(Element ele, BeanDefinition bd) { String indexAttr = ele.getAttribute("index"); String typeAttr = ele.getAttribute("type"); String nameAttr = ele.getAttribute("name"); if(StringUtils.hasLength(indexAttr)) { try { int value = Integer.parseInt(indexAttr); if(value < 0) { this.error("\'index\' cannot be lower than 0", ele); } else { try { this.parseState.push(new ConstructorArgumentEntry(value)); //解析constructor-arg Object valueHolder = this.parsePropertyValue(ele, bd, (String)null); //将type,name,index属性一并封装到valueHolder类型中。 ValueHolder valueHolder1 = new ValueHolder(valueHolder); if(StringUtils.hasLength(typeAttr)) { valueHolder1.setType(typeAttr); } if(StringUtils.hasLength(nameAttr)) { valueHolder1.setName(nameAttr); } valueHolder1.setSource(this.extractSource(ele)); if(bd.getConstructorArgumentValues().hasIndexedArgumentValue(value)) { this.error("Ambiguous constructor-arg entries for index " + value, ele); } else { //将valueHolder里面的type,name,index等,添加到BeanDefinition的ConstructorArgumentValues的IndexedArgumentValue属性中。 bd.getConstructorArgumentValues().addIndexedArgumentValue(value, valueHolder1); } } finally { this.parseState.pop(); } } } catch (NumberFormatException var19) { this.error("Attribute \'index\' of tag \'constructor-arg\' must be an integer", ele); } } else { //如果没有index属性则自动寻找 try { this.parseState.push(new ConstructorArgumentEntry()); //解析constructor-arg Object value1 = this.parsePropertyValue(ele, bd, (String)null); ValueHolder valueHolder2 = new ValueHolder(value1); if(StringUtils.hasLength(typeAttr)) { valueHolder2.setType(typeAttr); } if(StringUtils.hasLength(nameAttr)) { valueHolder2.setName(nameAttr); } valueHolder2.setSource(this.extractSource(ele)); //将valueHolder里面的type,name,index等,添加到BeanDefinition的ConstructorArgumentValues的genericArgumentValue属性中。 bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder2); } finally { this.parseState.pop(); } } }
关于 this.parseConstructorArgElements(ele, bd);的源码中的parsePropertyValue(Element ele, BeanDefinition bd, String propertyName)方法源码:
public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) { String elementName = propertyName != null?"<property> element for property \'" + propertyName + "\'":"<constructor-arg> element"; NodeList nl = ele.getChildNodes(); Element subElement = null; for(int hasRefAttribute = 0; hasRefAttribute < nl.getLength(); ++hasRefAttribute) { Node hasValueAttribute = nl.item(hasRefAttribute); //对应的description或者meta不处理。 if(hasValueAttribute instanceof Element && !this.nodeNameEquals(hasValueAttribute, "description") && !this.nodeNameEquals(hasValueAttribute, "meta")) { if(subElement != null) { this.error(elementName + " must not contain more than one sub-element", ele); } else { subElement = (Element)hasValueAttribute; } } } //解析constructor-arg的ref属性 boolean var11 = ele.hasAttribute("ref"); //解析constructor-arg的value属性 boolean var12 = ele.hasAttribute("value"); if(var11 && var12 || (var11 || var12) && subElement != null) { //如果同时有ref属性又有value属性,或者存在ref属性的同时有value属性且又有子元素,报错。 this.error(elementName + " is only allowed to contain either \'ref\' attribute OR \'value\' attribute OR sub-element", ele); } if(var11) { String var13 = ele.getAttribute("ref"); if(!StringUtils.hasText(var13)) { this.error(elementName + " contains empty \'ref\' attribute", ele); } //使用RuntimeBeanReference封装对应的ref名称<constructor-arg ref="a"> RuntimeBeanReference ref = new RuntimeBeanReference(var13); ref.setSource(this.extractSource(ele)); return ref; } else if(var12) { //使用TypedStringValue封装对应的value名称<constructor-arg value="a"> TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute("value")); valueHolder.setSource(this.extractSource(ele)); return valueHolder; } else if(subElement != null) { //子元素的处理 /** <constructor-arg> <map> <entry key="key" value="value"> </map> </constructor-arg> **/ return this.parsePropertySubElement(subElement, bd); } else { //没有ref也没有value也没有子元素,spring报错。 this.error(elementName + " must specify a ref or value", ele); return null; } }
子元素的处理 this.parsePropertySubElement(subElement, bd)源码根据源码可以看到constructor-arg支持的子元素
public Object parsePropertySubElement(Element ele, BeanDefinition bd) { return this.parsePropertySubElement(ele, bd, (String)null); } public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) { if(!this.isDefaultNamespace((Node)ele)) { return this.parseNestedCustomElement(ele, bd); } else if(this.nodeNameEquals(ele, "bean")) { BeanDefinitionHolder nullHolder2 = this.parseBeanDefinitionElement(ele, bd); if(nullHolder2 != null) { nullHolder2 = this.decorateBeanDefinitionIfRequired(ele, nullHolder2, bd); } return nullHolder2; } else if(this.nodeNameEquals(ele, "ref")) { String nullHolder1 = ele.getAttribute("bean"); boolean toParent = false; if(!StringUtils.hasLength(nullHolder1)) { nullHolder1 = ele.getAttribute("local"); if(!StringUtils.hasLength(nullHolder1)) { nullHolder1 = ele.getAttribute("parent"); toParent = true; if(!StringUtils.hasLength(nullHolder1)) { this.error("\'bean\', \'local\' or \'parent\' is required for <ref> element", ele); return null; } } } if(!StringUtils.hasText(nullHolder1)) { this.error("<ref> element contains empty target attribute", ele); return null; } else { RuntimeBeanReference ref = new RuntimeBeanReference(nullHolder1, toParent); ref.setSource(this.extractSource(ele)); return ref; } } else if(this.nodeNameEquals(ele, "idref")) { return this.parseIdRefElement(ele); } else if(this.nodeNameEquals(ele, "value")) { return this.parseValueElement(ele, defaultValueType); } else if(this.nodeNameEquals(ele, "null")) { TypedStringValue nullHolder = new TypedStringValue((String)null); nullHolder.setSource(this.extractSource(ele)); return nullHolder; } else if(this.nodeNameEquals(ele, "array")) { return this.parseArrayElement(ele, bd); } else if(this.nodeNameEquals(ele, "list")) { return this.parseListElement(ele, bd); } else if(this.nodeNameEquals(ele, "set")) { return this.parseSetElement(ele, bd); } else if(this.nodeNameEquals(ele, "map")) { return this.parseMapElement(ele, bd); } else if(this.nodeNameEquals(ele, "props")) { return this.parsePropsElement(ele); } else { this.error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele); return null; } }
解析子元素property,property的作用如下。
<bean id="test" class="test.TestClass"> <property name="testStr" value="aaa" /> </bean> 或者 <bean id="a"> <property name="p"> <list> <value>aa</value> <value>bb</value> </list> </property> </bean>
解析property的方法this.parsePropertyElements(ele, bd)源码为:
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(this.isCandidateElement(node) && this.nodeNameEquals(node, "property")) { this.parsePropertyElement((Element)node, bd); } } } //this.parsePropertyElement((Element)node, bd)的源码: public void parsePropertyElement(Element ele, BeanDefinition bd) { String propertyName = ele.getAttribute("name"); if(!StringUtils.hasLength(propertyName)) { this.error("Tag \'property\' must have a \'name\' attribute", ele); } else { this.parseState.push(new PropertyEntry(propertyName)); try { if(!bd.getPropertyValues().contains(propertyName)) { Object val = this.parsePropertyValue(ele, bd, propertyName); //将返回值使用PropertyValue进行封装,并记录在了BeanDefinition中的PropertyValues属性中。 PropertyValue pv = new PropertyValue(propertyName, val); this.parseMetaElements(ele, pv); pv.setSource(this.extractSource(ele)); bd.getPropertyValues().addPropertyValue(pv); return; } this.error("Multiple \'property\' definitions for property \'" + propertyName + "\'", ele); } finally { this.parseState.pop(); } } }
解析子元素qualifier,该元素的作用是,大多数时候都用注解的方式。解析的过程与前面相似。
public interface EmployeeService { public EmployeeDto getEmployeeById(Long id); } //上述接口的实现类 @Service("service") public class EmployeeServiceImpl implements EmployeeService { public EmployeeDto getEmployeeById(Long id) { return new EmployeeDto(); } } //上述接口的第二个实现类 @Service("service1") public class EmployeeServiceImpl1 implements EmployeeService { public EmployeeDto getEmployeeById(Long id) { return new EmployeeDto(); } } //控制层的调用代码如下: @Controller @RequestMapping("/emplayee.do") public class EmployeeInfoControl { @Autowired EmployeeService employeeService; } /** 此时启动tomcat会报错,因为该接口有两个实现类,spring不知道该去绑定哪一个,此时需要使用qualifier注解;问题解决。 **/ @Controller @RequestMapping("/emplayee.do") public class EmployeeInfoControl { @Autowired @Qualifier("service") EmployeeService employeeService; }
Qualifier的配置文件使用方法。
<bean id="myTestBean" class="bean.MyTestBean"> <qualifier type="org.Springframework.beans.factory.annotation.Qualifier" value="qf" /> </bean>
2.根据文章开头processBeanDefinition方法下面的bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder)的decorateBeanDefinitionIfRequired方法:该方法是用来解析默认标签中的自定义标签。
<!--解释一下此处的自定义标签,spring中以bean形式出现的标签分为默认和自定义, 而默认的bean中也有一些自定义标签,例如bean的属性。--> <!--实例:默认的bean标签自定义属性标签--> <bean id="test" class="test.MyClass"> <mybean:user username="aaa"> </bean>
//追踪decorateBeanDefinitionIfRequired方法 public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder definitionHolder) { return this.decorateBeanDefinitionIfRequired(ele, definitionHolder, (BeanDefinition)null); }
/** 可以看到decorateBeanDefinitionIfRequired的第三个参数是null,这里需要传>的是父类的beanDefinition,其实是为了使用父类的scope属性,以备子类没有设>置scope时默认使用父类的属性,此处是顶层配置,所以传递null。 **/ //继续跟踪decorateBeanDefinitionIfRequired public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, >BeanDefinitionHolder definitionHolder, BeanDefinition containingBd) { BeanDefinitionHolder finalDefinition = definitionHolder; NamedNodeMap attributes = ele.getAttributes(); //遍历所有属性,看看是否有适用于修饰的属性 for(int children = 0; children < attributes.getLength(); ++children) { Node i = attributes.item(children); finalDefinition = this.decorateIfRequired(i, finalDefinition, >containingBd); } NodeList var9 = ele.getChildNodes(); //遍历所有的子节点,看看是否有适用于修饰的子元素。 for(int var10 = 0; var10 < var9.getLength(); ++var10) { Node node = var9.item(var10); if(node.getNodeType() == 1) { finalDefinition = this.decorateIfRequired(node, finalDefinition, >containingBd); } } return finalDefinition; } //继续跟踪decorateIfRequired方法 public BeanDefinitionHolder decorateIfRequired(Node node, BeanDefinitionHolder originalDef, BeanDefinition containingBd) { //获取自定义标签的命名空间 String namespaceUri = this.getNamespaceURI(node); //对于非默认标签进行修饰。 if(!this.isDefaultNamespace(namespaceUri)) { //根据命名空间找到对应的处理器。 NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri); if(handler != null) { //进行修饰。此处在后面自定义标签处详细说明。 return handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd)); } if(namespaceUri != null && namespaceUri.startsWith("http://www.springframework.org/")) { this.error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", node); } else if(this.logger.isDebugEnabled()) { this.logger.debug("No Spring NamespaceHandler found for XML schema namespace [" + namespaceUri + "]"); } } return originalDef; }
3.根据文章开头processBeanDefinition方法下面的BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry())追踪:
public static void registerBeanDefinition(BeanDefinitionHolder >definitionHolder, BeanDefinitionRegistry registry) throws >BeanDefinitionStoreException { String beanName = definitionHolder.getBeanName(); //使用beanName做唯一标识。此处可以看出解析的beanDefinition都会被注册在BeanDefinitionRegistry类型的registry中。 registry.registerBeanDefinition(beanName, >definitionHolder.getBeanDefinition()); //注册所有的别名。 String[] aliases = definitionHolder.getAliases(); if(aliases != null) { String[] var4 = aliases; int var5 = aliases.length; for(int var6 = 0; var6 < var5; ++var6) { String alias = var4[var6]; registry.registerAlias(beanName, alias); } } } /** 对于beanDefinition的注册,其实就是将beanDefinition直接放入map中,使用beanName作为key。除此之外,spring还利用registerBeanDefinition做了一些其他的事。 **/ //继续追踪registerBeanDefinition方法: public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { Assert.hasText(beanName, "Bean name must not be empty"); Assert.notNull(beanDefinition, "BeanDefinition must not be null"); if(beanDefinition instanceof AbstractBeanDefinition) { try { /** 注册前的最后一次校验,此处的校验不同于之前的XML文件校验 主要是对于AbstractBeanDefinition属性中的methodOverrides校验 校验methodOverrides是否与工厂方法并存或者methodOverrides对应方法根本不存在。 **/ ((AbstractBeanDefinition)beanDefinition).validate(); } catch (BeanDefinitionValidationException var9) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", var9); } } BeanDefinition oldBeanDefinition = (BeanDefinition)this.beanDefinitionMap.get(beanName); if(oldBeanDefinition != null) { //如果对应的BeanName已经注册且在配置中配置了bean不允许被覆盖,则抛异常。 if(!this.isAllowBeanDefinitionOverriding()) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Cannot register bean definition [" + beanDefinition + "] for bean \'" + beanName + "\': There is already [" + oldBeanDefinition + "] bound."); } if(oldBeanDefinition.getRole() < beanDefinition.getRole()) { if(this.logger.isWarnEnabled()) { this.logger.warn("Overriding user-defined bean definition for bean \'" + beanName + "\' with a framework-generated bean definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } else if(!beanDefinition.equals(oldBeanDefinition)) { if(this.logger.isInfoEnabled()) { this.logger.info("Overriding bean definition for bean \'" + beanName + "\' with a different definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } else if(this.logger.isDebugEnabled()) { this.logger.debug("Overriding bean definition for bean \'" + >beanName + "\' with an equivalent definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } this.beanDefinitionMap.put(beanName, beanDefinition); } else { if(this.hasBeanCreationStarted()) { Map var4 = this.beanDefinitionMap; //beanDefinitionMap是全局变量,存在并发的情况。 synchronized(this.beanDefinitionMap) { this.beanDefinitionMap.put(beanName, beanDefinition); ArrayList updatedDefinitions = new ArrayList(this.beanDefinitionNames.size() + 1); updatedDefinitions.addAll(this.beanDefinitionNames); updatedDefinitions.add(beanName); this.beanDefinitionNames = updatedDefinitions; if(this.manualSingletonNames.contains(beanName)) { LinkedHashSet updatedSingletons = new LinkedHashSet(this.manualSingletonNames); updatedSingletons.remove(beanName); this.manualSingletonNames = updatedSingletons; } } } else { //注册beanDefinition this.beanDefinitionMap.put(beanName, beanDefinition); //记录对应的beanName this.beanDefinitionNames.add(beanName); this.manualSingletonNames.remove(beanName); } this.frozenBeanDefinitionNames = null; } if(oldBeanDefinition != null || this.containsSingleton(beanName)) { //重置所有beanName对应的缓存。 this.resetBeanDefinition(beanName); } } //继续追踪前一步的registerAlias方法,注册别名的方法: public void registerAlias(String name, String alias) { Assert.hasText(name, "\'name\' must not be empty"); Assert.hasText(alias, "\'alias\' must not be empty"); if(alias.equals(name)) { this.aliasMap.remove(alias); } else { String registeredName = (String)this.aliasMap.get(alias); if(registeredName != null) { if(registeredName.equals(name)) { return; } //如果alias不允许覆盖则抛出异常。 if(!this.allowAliasOverriding()) { throw new IllegalStateException("Cannot register alias \'" + >alias + "\' for name \'" + name + "\': It is already registered for name \'" + >registeredName + "\'."); } } //循环检查,A——>B存在时,如果再次出现A——>C——>B时则会抛出异常。 this.checkForAliasCircle(name, alias); this.aliasMap.put(alias, name); } }
4.最开始只解析了bean标签,此处补充alias和import和beans标签。
alias标签的解析。
首先解释一下alias的作用,在对bean进行定义时,除了使用id属性来指定名称以外,为了提供多个名称,可以使用alias标签来指定。
<!--例如--> <bean id="testBean" class="com.test"> <!--给这个JavaBean添加别名的第一种方式--> <bean id="testBean" name="testBean,testBean2" class="com.test"/> <!--给这个JavaBean添加别名的第二种方式--> <bean id="testBean" class="com.test"/> <alias name="testBean" alias="testBean,testBean2"/> <!--第二个例子:组件A在XML配置文件中定义了一个名为componentA的DataSource类型的bean,但是组件B却想在其XML文件中以componentB命名来引用此bean。而且在主程序MyApp的XML配置文件中,希望以myApp的名字来引用此bean。最后容器加载3个XML来生成最终的ApplicationContext。--> <alias name="componentA" alias="componentB"/> <alias name="componentA" alias="myApp"/>
查看this.processAliasRegistration(ele)源码
protected void processAliasRegistration(Element ele) { //读取beanName String name = ele.getAttribute("name"); //获取alias String alias = ele.getAttribute("alias"); boolean valid = true; if(!StringUtils.hasText(name)) { this.getReaderContext().error("Name must not be empty", ele); valid = false; } if(!StringUtils.hasText(alias)) { this.getReaderContext().error("Alias must not be empty", ele); valid = false; } if(valid) { try { this.getReaderContext().getRegistry().registerAlias(name, alias); } catch (Exception var6) { this.getReaderContext().error("Failed to register alias \'" + alias + "\' for bean with name \'" + name + "\'", ele, var6); } //别名注册以后通知监听器做相应处理。 this.getReaderContext().fireAliasRegistered(name, alias, this.extractSource(ele)); } }
impot标签的解析
首先解释一下import标签的作用,将配置文件分块,利用import导入多个配置文件。
<?xml version="1.0" encoding="gb2312"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <import resource="CTIContext.xml" /> <import resource="customerContext.xml" /> <import resource="customerServingContext.xml" /> <import resource="manageContext.xml" /> <import resource="routineContext.xml" /> <import resource="systemContext.xml" /> ........... </beans>
this.importBeanDefinitionResource(ele)的源码:
protected void importBeanDefinitionResource(Element ele) { //获取resource属性。 String location = ele.getAttribute("resource"); //如果不存在resource属性则不做任何处理。 if(!StringUtils.hasText(location)) { this.getReaderContext().error("Resource location must not be empty", ele); } else { //解析系统属性,格式如:"${user.dir}" location = this.getReaderContext().getEnvironment().resolveRequiredPlaceholders(location); //判定location是URI是绝对的还是相对的。 boolean absoluteLocation = false; try { absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute(); } catch (URISyntaxException var11) { ; } int actResArray; //如果是绝对URI则直接根据地址加载对应的配置文件。 if(absoluteLocation) { try { actResArray = this.getReaderContext().getReader().loadBeanDefinitions(location, actualResources); if(this.logger.isDebugEnabled()) { this.logger.debug("Imported " + actResArray + " bean definitions from URL location [" + location + "]"); } } catch (BeanDefinitionStoreException var10) { this.getReaderContext().error("Failed to import bean definitions from URL location [" + location + "]", ele, var10); } } else { //如果是相对地址则根据相对地址计算出绝对地址。 try { Resource relativeResource = this.getReaderContext().getResource().createRelative(location); if(relativeResource.exists()) { actResArray = this.getReaderContext().getReader().loadBeanDefinitions(relativeResource); actualResources.add(relativeResource); } else { //如果解析不成功,则使用默认的解析器 String baseLocation = this.getReaderContext().getResource().getURL().toString(); actResArray = this.getReaderContext().getReader().loadBeanDefinitions(StringUtils.applyRelativePath(baseLocation, location), actualResources); } if(this.logger.isDebugEnabled()) { this.logger.debug("Imported " + actResArray + " bean definitions from relative location [" + location + "]"); } } catch (IOException var8) { this.getReaderContext().error("Failed to resolve current resource location", ele, var8); } catch (BeanDefinitionStoreException var9) { this.getReaderContext().error("Failed to import bean definitions from relative location [" + location + "]", ele, var9); } } //解析后进行监听器激活处理。 Resource[] actResArray1 = (Resource[])actualResources.toArray(new Resource[actualResources.size()]); this.getReaderContext().fireImportProcessed(location, actResArray1, this.extractSource(ele)); } }
嵌入式beans标签的解析
xbeans标签与单独的配置文件并没有太大差别,是递归调用bean的解析过程。
相关文章推荐
- Spring源码解析(2)之默认标签的解析(一)
- Spring源码解析之一 ------ 默认标签的解析注册(IOC的第一步)
- Spring源码解析之默认标签的解析
- spring 源码探索--xml的默认标签解析
- Spring源码解析:默认标签的解析过程
- spring源码剖析(二)Spring默认标签解析及注册实现
- Spring源码解析-默认标签的解析
- Spring源码解密之默认标签的解析
- Spring源码解析(四)——默认标签解析
- Spring源码解析(2)之默认标签的解析(二)
- spring 3源码解析之如何解析"import", "alias", "bean"标签
- spring 源码探索 -- aop 标签解析和创建代理
- spring默认启动位置以及contextConfigLocation设置源码解析
- spring 源码探索--xml的自定义标签解析
- spring默认标签解析
- spring源码附录(8)import、beans标签的解析
- spring源码剖析(四)自定义标签解析流程
- spring源码剖析(四)自定义标签解析流程
- spring源码解析之默认配置文件名/WEB-INF/applicationContext.xml
- spring源码(7)alias标签的解析