前文讲了,这里写了所有Spring可以配置的属性、节点等等。比如我们常见的:<property>、<constructor-arg>等,也包括我们很少用的元信息(meta)、qualifier等,当然也有我们在bean里面配置的scope等。先看下简代码:
代码1.1:BeanDefinitionParserDelegate类的parseBeanDefinitionElement方法 public AbstractBeanDefinition parseBeanDefinitionElement( Element ele, String beanName, BeanDefinition containingBean) { ... 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); } AbstractBeanDefinition bd = createBeanDefinition(className, parent); //这里面设置scope、abstract、lazy-init等 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); //设置property属性 parsePropertyElements(ele, bd); parseQualifierElements(ele, bd); bd.setResource(this.readerContext.getResource()); bd.setSource(extractSource(ele)); ... }这里我们将两个比较有代表性的parseBeanDefinitionAttributes方法和parseConstructorArgElements方法。先来看第一个方法的代码。
代码1.2:BeanDefinitionParserDelegate类的parseBeanDefinitionAttributes方法 public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName, BeanDefinition containingBean, AbstractBeanDefinition bd) { //设置scope属性 if (ele.hasAttribute(SCOPE_ATTRIBUTE)) { bd.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)) { bd.setScope(TRUE_VALUE.equals(ele.getAttribute(SINGLETON_ATTRIBUTE)) ? BeanDefinition.SCOPE_SINGLETON : BeanDefinition.SCOPE_PROTOTYPE); } else if (containingBean != null) { //设置默认,也就是空 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 (DEFAULT_VALUE.equals(lazyInit)) { lazyInit = this.defaults.getLazyInit(); } bd.setLazyInit(TRUE_VALUE.equals(lazyInit)); //设置自动装配属性 String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE); bd.setAutowireMode(getAutowireMode(autowire)); //设置dependency-check String dependencyCheck = ele.getAttribute(DEPENDENCY_CHECK_ATTRIBUTE); bd.setDependencyCheck(getDependencyCheck(dependencyCheck)); //设置depends-on if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) { String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE); bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, BEAN_NAME_DELIMITERS)); } //设置autowire-candidate 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)); } //设置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); if (!"".equals(initMethodName)) { 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); if (!"".equals(destroyMethodName)) { 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; }上面这个方法是对<bean></bean>里面的配置,一般都是通过直接set的方式。有一点大家注意一下,赋值的是AbstractBeanDefinition抽象类,BeanDefinition是一个接口,AbstractBeanDefinition实现了该接口,并将一些赋值方法做了重写等,它是BeanDefinition的升级版。
我们重点看parsePropertyElements方法。
代码1.3:BeanDefinitionParserDelegate类的parsePropertyElements方法 //该方法--调用入口public void parsePropertyElements(Element beanEle, BeanDefinition bd) { //获取<Bean>元素中所有的子元素 NodeList nl = beanEle.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); //如果子元素是<property>子元素,则调用解析<property>子元素方法解析 if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) { parsePropertyElement((Element) node, bd); } } } //该方法--解析<property>元素 public void parsePropertyElement(Element ele, BeanDefinition bd) { //获取<property>元素的名字 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 { //如果一个Bean中已经有同名的property存在,则不进行解析,直接返回。 //即如果在同一个Bean中配置同名的property,则只有第一个起作用 if (bd.getPropertyValues().contains(propertyName)) { error("Multiple 'property' definitions for property '" + propertyName + "'", ele); return; } //解析获取property的值 Object val = parsePropertyValue(ele, bd, propertyName); //根据property的名字和值创建property实例 PropertyValue pv = new PropertyValue(propertyName, val); //解析<property>元素中的属性 parseMetaElements(ele, pv); pv.setSource(extractSource(ele)); bd.getPropertyValues().addPropertyValue(pv); } finally { this.parseState.pop(); } }我们继续看下解析获取property值的方法parsePropertyValue,该方法也适用于constructor arguments(构造器参数),只不过propertyName为空就行。来看代码:
代码1.4:BeanDefinitionParserDelegate类的parsePropertyValue方法 public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) { String elementName = (propertyName != null) ? "<property> element for property '" + propertyName + "'" : "<constructor-arg> element"; //获取<property>的所有子元素,只能是其中一种类型:ref,value,list等 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)) { if (subElement != null) { error(elementName + " must not contain more than one sub-element", ele); } else {//当前<property>元素包含有子元素 subElement = (Element) node; } } } //判断property的属性值是ref还是value,不允许既是ref又是value 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); } //如果属性是ref,创建一个ref的数据对象RuntimeBeanReference,这个对象封装了ref信息 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的数据对象是被当前的property对象所引用 ref.setSource(extractSource(ele)); return ref; } //如果属性是value,创建一个value的数据对象TypedStringValue,这个对象封装了value信息 else if (hasValueAttribute) { //持有String类型值的对象 [这里一般我们都配class的路径,因为不实例化,所以这样处理] TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE)); valueHolder.setSource(extractSource(ele)); return valueHolder; } else if (subElement != null) {//如果当前<property>元素还有子元素 return parsePropertySubElement(subElement, bd); } else { // 既不是"ref"又不是"value",报错 error(elementName + " must specify a ref or value", ele); return null; } }通过对上述源码的分析,我们可以了解在Spring配置文件中,<Bean>元素中<property>元素的相关配置是如何处理的: (1). ref被封装为指向依赖对象一个引用。 (2). value配置都会封装成一个字符串类型的对象。 (3). ref和value都通过“解析的数据类型属性值.setSource(extractSource(ele))方法将属性值/引用与所引用的属性关联起来。 (4).无论是ref/value/Collection,都只能有一个。
