spring源码阅读(七)之bean解析

来源:互联网 发布:libevent windows 编译 编辑:程序博客网 时间:2024/05/03 19:42
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {processBeanDefinition(ele, delegate);}

上一篇介绍的节点判断,如果是bean节点则调用processBeanDefinition这个方法。

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {String id = ele.getAttribute(ID_ATTRIBUTE);获取id属性String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);获取名称属性List<String> aliases = new ArrayList<String>();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.isDebugEnabled()) {这里如果定义bean的名称name属性的话就取其别名logger.debug("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);// 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.isDebugEnabled()) {logger.debug("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;}

首先是获取属性public static final String ID_ATTRIBUTE = "id";public static final String MULTI_VALUE_ATTRIBUTE_DELIMITERS = ",; ";很好的编程习惯。上面的代码有一个checkNameUniqueness它是校验这个bean是否已存在,如果有则报错

protected void checkNameUniqueness(String beanName, List<String> aliases, Element beanElement) {String foundName = null;if (StringUtils.hasText(beanName) && this.usedNames.contains(beanName)) {//判断bena名称是否存在foundName = beanName;}if (foundName == null) {foundName = (String) CollectionUtils.findFirstMatch(this.usedNames, aliases);<span style="font-family: Arial, Helvetica, sans-serif;">//判断bena别名是否存在</span>}if (foundName != null) {error("Bean name '" + foundName + "' is already used in this <beans> element", beanElement);}this.usedNames.add(beanName);this.usedNames.addAll(aliases);//如果都不存在万事大吉可以加入usedNames这个集合。}
我去太严谨了 private final Set<String> usedNames = new HashSet<String>();这个本来就是一个不能重复字符串的set集合。

程序到了最重要的一个部分

AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);这句话完成装换。ok看如何实现。这个方法稍微有点复杂,慢慢看吧。

public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, BeanDefinition containingBean) {this.parseState.push(new BeanEntry(beanName));String className = null;if (ele.hasAttribute(CLASS_ATTRIBUTE)) {className = ele.getAttribute(CLASS_ATTRIBUTE).trim();}try {String parent = null;if (ele.hasAttribute(PARENT_ATTRIBUTE)) {parent = ele.getAttribute(PARENT_ATTRIBUTE);}AbstractBeanDefinition bd = createBeanDefinition(className, parent);//这里构造这个BeanDefinition而且有了className和parent这个属性parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);//这个方法是给他添加方法和属性,内容很多bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));parseMetaElements(ele, bd);//bean里面包含的属性<span style="font-family: Consolas, 'Courier New', Courier, mono, serif; line-height: 18px; background-color: rgb(248, 248, 248);"> </span><span class="tag" style="margin: 0px; padding: 0px; border: none; color: rgb(153, 51, 0); background-color: rgb(248, 248, 248); font-weight: bold; font-family: Consolas, 'Courier New', Courier, mono, serif; line-height: 18px;"><</span><span class="tag-name" style="margin: 0px; padding: 0px; border: none; color: rgb(153, 51, 0); background-color: rgb(248, 248, 248); font-weight: bold; font-family: Consolas, 'Courier New', Courier, mono, serif; line-height: 18px;">meta</span><span style="margin: 0px; padding: 0px; border: none; background-color: rgb(248, 248, 248); font-family: Consolas, 'Courier New', Courier, mono, serif; line-height: 18px;"> </span><span class="attribute" style="margin: 0px; padding: 0px; border: none; color: red; background-color: rgb(248, 248, 248); font-family: Consolas, 'Courier New', Courier, mono, serif; line-height: 18px;">key</span><span style="margin: 0px; padding: 0px; border: none; background-color: rgb(248, 248, 248); font-family: Consolas, 'Courier New', Courier, mono, serif; line-height: 18px;">=</span><span class="attribute-value" style="margin: 0px; padding: 0px; border: none; color: blue; background-color: rgb(248, 248, 248); font-family: Consolas, 'Courier New', Courier, mono, serif; line-height: 18px;">"j2:cat"</span><span style="margin: 0px; padding: 0px; border: none; background-color: rgb(248, 248, 248); font-family: Consolas, 'Courier New', Courier, mono, serif; line-height: 18px;"> </span><span class="attribute" style="margin: 0px; padding: 0px; border: none; color: red; background-color: rgb(248, 248, 248); font-family: Consolas, 'Courier New', Courier, mono, serif; line-height: 18px;">value</span><span style="margin: 0px; padding: 0px; border: none; background-color: rgb(248, 248, 248); font-family: Consolas, 'Courier New', Courier, mono, serif; line-height: 18px;">=</span><span class="attribute-value" style="margin: 0px; padding: 0px; border: none; color: blue; background-color: rgb(248, 248, 248); font-family: Consolas, 'Courier New', Courier, mono, serif; line-height: 18px;">"xmlPageManager orpageSerializer"</span><span style="margin: 0px; padding: 0px; border: none; background-color: rgb(248, 248, 248); font-family: Consolas, 'Courier New', Courier, mono, serif; line-height: 18px;"> </span><span class="tag" style="margin: 0px; padding: 0px; border: none; color: rgb(153, 51, 0); background-color: rgb(248, 248, 248); font-weight: bold; font-family: Consolas, 'Courier New', Courier, mono, serif; line-height: 18px;">/></span><span style="margin: 0px; padding: 0px; border: none; background-color: rgb(248, 248, 248); font-family: Consolas, 'Courier New', Courier, mono, serif; line-height: 18px;">  </span>parseLookupOverrideSubElements(ele, bd.getMethodOverrides());parseReplacedMethodSubElements(ele, bd.getMethodOverrides());parseConstructorArgElements(ele, bd);//<span class="tag" style="margin: 0px; padding: 0px; border: none; color: rgb(153, 51, 0); font-weight: bold; font-family: Consolas, 'Courier New', Courier, mono, serif; line-height: 18px;"></</span><span class="tag-name" style="margin: 0px; padding: 0px; border: none; color: rgb(153, 51, 0); font-weight: bold; font-family: Consolas, 'Courier New', Courier, mono, serif; line-height: 18px;">constructor-arg</span><span class="tag" style="margin: 0px; padding: 0px; border: none; color: rgb(153, 51, 0); font-weight: bold; font-family: Consolas, 'Courier New', Courier, mono, serif; line-height: 18px;">></span><span style="margin: 0px; padding: 0px; border: none; font-family: Consolas, 'Courier New', Courier, mono, serif; line-height: 18px;">  </span>parsePropertyElements(ele, bd);// <property name="proxyTargetClass" value="true" /> 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;}
BeanDefinition就是对bean的抽象,下面的方法将是给他添加方法和属性的
public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,BeanDefinition containingBean, AbstractBeanDefinition bd) {if (ele.hasAttribute(SCOPE_ATTRIBUTE)) {//添加Scope属性// Spring 2.x "scope" attributebd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {error("Specify either 'scope' or 'singleton', not both", ele);}}else if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {<span style="font-family: Arial, Helvetica, sans-serif;">//添加单例属性</span>// Spring 1.x "singleton" attributebd.setScope(TRUE_VALUE.equals(ele.getAttribute(SINGLETON_ATTRIBUTE)) ?BeanDefinition.SCOPE_SINGLETON : BeanDefinition.SCOPE_PROTOTYPE);}else if (containingBean != null) {// Take default from containing bean in case of an inner bean definition.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 (DEFAULT_VALUE.equals(lazyInit)) {//初始化是是否懒加载lazyInit = this.defaults.getLazyInit();}bd.setLazyInit(TRUE_VALUE.equals(lazyInit));//LazyInit属性String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);bd.setAutowireMode(getAutowireMode(autowire));//autowire属性String dependencyCheck = ele.getAttribute(DEPENDENCY_CHECK_ATTRIBUTE);bd.setDependencyCheck(getDependencyCheck(dependencyCheck));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 ("".equals(autowireCandidate) || DEFAULT_VALUE.equals(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);if (!"".equals(initMethodName)) {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);if (!"".equals(destroyMethodName)) {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;}

上面的方法是解析bean自身属性的下面还将举一个解析Property的方法,我们在代码里面经常会写<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator">
    <property name="proxyTargetClass" value="true" /> 
  </bean>

这个property 标签

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)) {如果同名的property属性已存在,则只能第一个生效,代码直接returnerror("Multiple 'property' definitions for property '" + propertyName + "'", ele);return;}Object val = parsePropertyValue(ele, bd, propertyName);这里取得<span style="font-family: Arial, Helvetica, sans-serif;">property的可能是集合也可能是其他的,下面会进入这个方法</span>PropertyValue pv = new PropertyValue(propertyName, val);parseMetaElements(ele, pv);pv.setSource(extractSource(ele));bd.getPropertyValues().addPropertyValue(pv);}finally {this.parseState.pop();}}
这个标签有的时候可能也很复杂譬如
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" >
<property name="messageConverters">   
         <list>   
             <bean class = "org.springframework.http.converter.StringHttpMessageConverter">   
                <property name = "supportedMediaTypes">
                      <list>
                          <value>application/json;charset=UTF-8</value>   
                     </list>   
                </property>   
             </bean>   
         </list>   
   </property>  
</bean>
所以上面的方法会很多内容

public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) {String elementName = (propertyName != null) ?"<property> element for property '" + propertyName + "'" :"<constructor-arg> element";// Should only have one child element: ref, value, list, etc.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)) {// 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;//获取子节点}}}boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);这里要么是value要么是ref不能都有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) {如果是refString 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) {如果是valueTypedStringValue 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.error(elementName + " must specify a ref or value", ele);return null;}}

下面将介绍property 子节点怎么样遍历
public Object parsePropertySubElement(Element ele, BeanDefinition bd, 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)) {// 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 the same XML file.refName = ele.getAttribute(LOCAL_REF_ATTRIBUTE);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', 'local' 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)) {// 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;}}
上面的方法里面做了很多分支,应对各种情况介绍一种对list的解析

public List parseListElement(Element collectionEle, BeanDefinition bd) {String defaultElementType = collectionEle.getAttribute(VALUE_TYPE_ATTRIBUTE);NodeList nl = collectionEle.getChildNodes();ManagedList<Object> target = new ManagedList<Object>(nl.getLength());target.setSource(extractSource(collectionEle));target.setElementTypeName(defaultElementType);target.setMergeEnabled(parseMergeAttribute(collectionEle));parseCollectionElements(nl, target, bd, defaultElementType);return target;}
里面调用parseCollectionElements
protected void parseCollectionElements(NodeList elementNodes, Collection<Object> target, 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));回调parsePropertySubElement这个方法}}}
终于把所有属性方法都遍历了,这样都封装在BeanDefinition里面,但这还没有全部完成。下一篇,怎样注册





0 0