• spring源码分析——默认标签的解析


    上一节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中

  • 相关阅读:
    SQLServer性能诊断与调优
    (转).NET面试题整理之基础篇
    (转)[茗洋芳竹]程序员常用不常见很难得的地址大全,博主很辛苦
    (转)页面过度动画效果大集合
    (转)软件开发和团队”最小模式”初探2-6人模型(下)
    silverlight 乐动魔方 实战九 .
    (转)js+flash实现手写输入功能特效
    (转)软件开发和团队”最小模式”初探2-6人模型(上)
    (转)我眼中的PM
    silverlight 乐动魔方 实战十 .
  • 原文地址:https://www.cnblogs.com/warrior4236/p/13143743.html
Copyright © 2020-2023  润新知