上一节spring源码分析,看到spring将xml文件封装成了Document对象,然后委托给BeanDefinitionDocumentReader来解析,从parseBeanDefinitions这个方法开始看,
一:解析默认元素bean
1:解析的流程
看一下delegate如何解析bean元素:
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) { // bean元素的属性 id、name(别名,可以配置多个 以,;分隔) 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)); } // id就是bean的名称,如果id没有配置,但是name配置了,就使用name的值作为bean的名称 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) { // 检查配置的beanName和别名是否唯一,之前是否有bean已经使用了这个名称 checkNameUniqueness(beanName, aliases, ele); } // 创建beanDefinition对象 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.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; }
看一下这个方法:
解析bean元素的属性、子元素的主要逻辑都在这个方法里面:
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 { // 根据className和parent来创建beanDefinition AbstractBeanDefinition bd = createBeanDefinition(className, parent); // 解析元素的属性 parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT)); /** * 以下解析的都是元素的子标签 meta、lookup-method、replaced-method、constructorArgs * property、qualifier */ // 解析元数据meta parseMetaElements(ele, bd); // 解析lookup-method子元素 parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); // 解析replaced-method子元素 parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); // 解析构造器注入 parseConstructorArgElements(ele, bd); // 解析set属性注入 parsePropertyElements(ele, bd); // 解析qualifier 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; }
解析class 以及 parent属性的值
创建beanDefinition对象:
2:解析set属性依赖注入
<property name="id" value="111"/>
<property name="dog" ref="dog"/>
入参为bean这个元素,以及刚刚创建的beanDefinition对象
首先解析到property上的name元素,然后根据name元素解析value的值,最后把name和value封装到PropertyValue对象上,设置到BeanDefinition上。
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)); // name和value的值都被封装到propertyValue对象上,然后在封装到db对象上 bd.getPropertyValues().addPropertyValue(pv); } finally { this.parseState.pop(); } }
这里的根据propertyName获取值,有value ref 子元素等方式,具体解析的细节不在这里分析,这里只分析流程
3:解析构造函数注入方式
遍历并且解析子元素:
/** * Parse a constructor-arg element. */ 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); // 如果包含index属性 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)); // 解析value的值 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)); // 如果index索引重复,那么赋值时会报错 if (bd.getConstructorArgumentValues().hasIndexedArgumentValue(index)) { error("Ambiguous constructor-arg entries for index " + index, ele); } else { // 把index与valueHolder封装到ConstructorArgumentValues对象,再把该对象设置到bd上 bd.getConstructorArgumentValues().addIndexedArgumentValue(index, valueHolder); } } finally { this.parseState.pop(); } } } catch (NumberFormatException ex) { error("Attribute 'index' of tag 'constructor-arg' must be an integer", ele); } } // 如果index不存在 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)); // 会把valueHolder的值封装到GenericArgumengValue中 bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder); } finally { this.parseState.pop(); } } }
第一种,包含index索引的情况:
解析元素的value值,过程和解析set注入property的流程一样,然后封装到valueHolder对象中,最后把index 和 valueHolder设置到beanDefinition的contructorArgumentValues的属性上
其他的元素也是一样,解析完成后,把名称、类型以及值的信息封装到对象上,然后设置到beanDefinition对象上。
bean元素解析完成,将属性设置到beanDefinition对象上,然后返回到上一步,封装到了BeanDefinitionHolder对象上维护。
返回bdHolder对象后,如果不为null,会对它进行一个包装(自定义标签的解析,后面章节分析),然后注册。
注册beanDefinition对象以及beanName
注册就是把beanDefinition放入beanDefinitionMap的缓存中,key为beanName,value 为beanDefinition对象,beanNames放入beanDefinitionNames缓存中
注册别名:
// 注册别名 @Override public void registerAlias(String name, String alias) { Assert.hasText(name, "'name' must not be empty"); Assert.hasText(alias, "'alias' must not be empty"); synchronized (this.aliasMap) { // 如果别名和beanName相等,则从别名缓存中删除别名,然后报错 if (alias.equals(name)) { this.aliasMap.remove(alias); if (logger.isDebugEnabled()) { logger.debug("Alias definition '" + alias + "' ignored since it points to same name"); } } else { String registeredName = this.aliasMap.get(alias); if (registeredName != null) { // 别名已经存在 if (registeredName.equals(name)) { // An existing alias - no need to re-register return; } // 不允许重写报错 if (!allowAliasOverriding()) { throw new IllegalStateException("Cannot define alias '" + alias + "' for name '" + name + "': It is already registered for name '" + registeredName + "'."); } if (logger.isDebugEnabled()) { logger.debug("Overriding alias '" + alias + "' definition for registered name '" + registeredName + "' with new target name '" + name + "'"); } } checkForAliasCircle(name, alias); // 放入别名缓存 this.aliasMap.put(alias, name); if (logger.isTraceEnabled()) { logger.trace("Alias definition '" + alias + "' registered for name '" + name + "'"); } } } }
到这里默认标签的解析工作就完成了
总结:默认标签主要包括import bean alias 等,以bean元素为例,
1:首先解析id class 属性,创建beanDefinition对象
2:解析bean元素可能配置的属性,子元素等信息 例如:property元素,constructor元素,lookup 等元素,解析完成后,
将数据封装到对应的对象上,然后设置到beanDefinition对象属性中,然后返回。
3:将beanDefinition放在到holder上,判断默认元素是否包含自定义元素,包括则进行解析,将数据设置到beanDefinition对象上
4:注册,注册beanDefinition到beanDefinitionMap集合中,注册beanName到beanDefinitionNames集合中,注册别名到aliasMap中