Spring读源码系列02----默认标签解析过程

Posted 大忽悠爱忽悠

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring读源码系列02----默认标签解析过程相关的知识,希望对你有一定的参考价值。

Spring读源码系列02----默认标签解析过程


阅读本系列之前,建议先从本专栏的两个不同视角学习spring的系列作为入门学习点(这两个系列会持续更新),先大体理解spring的架构设计与精髓,然后再来阅读本系列,深入源码分析,而不再纸上谈兵。

从整体来学spring系列文章:

Spring复杂的BeanFactory继承体系该如何理解? ----上

Spring复杂的BeanFactory继承体系该如何理解? ----中

Spring复杂的BeanFactory继承体系该如何理解?—中下

Spring复杂的BeanFactory继承体系该如何理解?—下

Spring复杂的IOC容器之短小的注解篇

Spring繁华的AOP王国—第一讲

Spring繁华的AOP王国—第二讲

Spring繁华的AOP王国—第三讲

Spring繁华的AOP王国----第四讲

Spring繁华的AOP王国—第五讲之应用案例和扩展

该系列持续更新中…


独特视角学习spring系列文章:

不一样的视角来学习Spring源码之容器与Bean—上

不一样的视角来学习Spring源码之容器与Bean—下

不一样的视角来学习Spring源码之AOP—上

不一样的视角来学习Spring源码之AOP—中

不一样的视角来学习Spring源码之AOP—下

该系列持续更新中…


本系列文章:

Spring读源码系列01—Spring核心类及关联性介绍


之前的流程建议大家看一下01篇

这里一句话简单概括一下01篇的流程: 定位xml文件资源,包装为Resource对象—>xml文件被解析为一颗DOM树,即Document对象—>BeanDefinitionDocumentReader负责对Document对象进行解析—>BeanDefinitionDocumentReader内部又把解析Document对象的事情委托给了BeanDefinitionParserDelegate来完成

	private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) 
	    //对imprt标签进行处理
		if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) 
			importBeanDefinitionResource(ele);
		
		//对alias标签进行处理
		else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) 
			processAliasRegistration(ele);
		
		//对bean标签进行处理
		else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) 
			processBeanDefinition(ele, delegate);
		
			//对beans标签进行处理
		else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) 

			doRegisterBeanDefinitions(ele);
		
	

Bean标签的解析及注册

DefaultBeanDefinitionDocumentReader#processBeanDefinition----对Bean标签进行处理的方法

	/**
	 * Process the given bean element, parsing the bean definition
	 * and registering it with the registry.
	 */
	protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) 
	    //委托BeanDefinitionParserDelegate来对bean标签进行解析
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
		if (bdHolder != null) 
		//对自定义子标签再进行处理---如果存在的话
			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
			try 
				// Register the final decorated instance.
				//注册BeanDefinition
				BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
			
			catch (BeanDefinitionStoreException ex) 
				getReaderContext().error("Failed to register bean definition with name '" +
						bdHolder.getBeanName() + "'", ele, ex);
			
			// Send registration event.
			//释放事件
			getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
		
	


BeanDefinitionParserDelegate#parseBeanDefinitionElement从xml配置信息—>BeanDefinition

	public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) 
	//这里的ele是bean标签
		return parseBeanDefinitionElement(ele, null);
	

目标方法:

	/**
	 * Parses the supplied <bean> element. May return null
	 * if there were errors during parse. Errors are reported to the
	 */
	@Nullable
	public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) 
	   //解析id属性
		String id = ele.getAttribute(ID_ATTRIBUTE);
		//解析name属性
		String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
        
        //存放bean的别名的集合 
		List<String> aliases = new ArrayList<>();
		if (StringUtils.hasLength(nameAttr)) 
		//分割name属性---得到的是别名数组
			String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
			//加入别名集合
			aliases.addAll(Arrays.asList(nameArr));
		
        
        //id规定了beanName   
		String beanName = id;
		if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) 
		    //beanName为空,就把别名数组中第一个元素拿出来作为beanName
			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) 
		    //别名不能重复
			checkNameUniqueness(beanName, aliases, ele);
		
         
        / 
		//传入bean标签,beanName,containingBean开始正式对bean标签进行解析得到beanDefinition
	   //返回的beanDefinition类型是GenericBeanDefinition
		AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
		///
		
		if (beanDefinition != null) 
		//beanName为空---没给id,别名也没有该咋办?
			if (!StringUtils.hasText(beanName)) 
				try 
				//containingBean不为空
					if (containingBean != null)
					 
					 //自动生成一个beanName
						beanName = BeanDefinitionReaderUtils.generateBeanName(
								beanDefinition, this.readerContext.getRegistry(), true);
					
					else 
					//如果containingBean为空,那就通过下面的方式生成一个beanName
					//这里获得的beanName是全类名加上一个#0---->org.deepSpring.Bean#0
						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);
			//生成BeanDefinitionHolder----这个类干的事情就是整合了beanDefinition,beanName和aliasesArray
			return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
		

		return null;
	



BeanDefinitionParserDelegate#parseBeanDefinitionElement—将bean标签映射到BeanDefinition

记住该类BeanDefinitionParserDelegate才是被委托解析xml生成BeanDefinition的对象

	/**
	 * Parse the bean definition itself, without regard to name or aliases. May return
	 null if problems occurred during the parsing of the bean definition.
	 */
	@Nullable
	public AbstractBeanDefinition parseBeanDefinitionElement(
			Element ele, String beanName, @Nullable BeanDefinition containingBean) 
       //跟踪解析的状态
		this.parseState.push(new BeanEntry(beanName));

		String className = null;
		if (ele.hasAttribute(CLASS_ATTRIBUTE)) 
		//获取bean标签里面的className属性
			className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
		
		String parent = null;
		if (ele.hasAttribute(PARENT_ATTRIBUTE)) 
		//获取bean标签里面的parent属性
			parent = ele.getAttribute(PARENT_ATTRIBUTE);
		

		try 
		    //生成BeanDefinition
			AbstractBeanDefinition bd = createBeanDefinition(className, parent);
           
           //硬编码解析默认bean的各种属性---因为BeanDefinition里面成员属性和bean标签里面能写的属性一一映射
           //这样的话,每解析出一个属性,就直接设置BeanDefinition对应映射到的值即可
			parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
			//提取description
			bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
            
            //解析元数据 
			parseMetaElements(ele, bd);
			//解析lookup-method属性
			parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
			//解析replace-method属性
			parseReplacedMethodSubElements(ele, bd.getMethodOverrides());

           //解析构造函数参数
			parseConstructorArgElements(ele, bd);
			//解析property子元素
			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;
	


BeanDefinitionParserDelegate#createBeanDefinition创建用于属性承载的BeanDefinition



	protected AbstractBeanDefinition createBeanDefinition(@Nullable String className, @Nullable String parentName)
			throws ClassNotFoundException 
           //BeanDefinitionReaderUtils来创建BeanDefinition
           //这个工具类还可以用来生成beanName,注册BeanDefinition上面都讲到过了
		return BeanDefinitionReaderUtils.createBeanDefinition(
				parentName, className, this.readerContext.getBeanClassLoader());
	
BeanDefinitionReaderUtils:

	public static AbstractBeanDefinition createBeanDefinition(
			@Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException 
        //创建的是GenericBeanDefinition
		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;
	


BeanDefinitionParserDelegate#parseBeanDefinitionAttributes—解析bean标签上能标注的各种属性


下面我们开始对bean标签里面的属性进行解析了

	/**
	 * Apply the attributes of the given bean element to the given bean * definition.
	 * @param ele bean declaration element
	 * @param beanName bean name
	 * @param containingBean containing bean definition
	 * @return a bean definition initialized according to the bean element attributes
	 */
	public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
			@Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) 
        //解析scope属性  
		if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) 
			error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);
		
		else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) 
			bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));
		
		else if (containingBean != null) 
		     //如果是内嵌的beanDefinition情况下,没有单独指定scope属性,则使用父类的默认属性    
			// Take default from containing bean in case of an inner bean definition.
			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 (isDefaultValue(lazyInit)) 
			lazyInit = this.defaults.getLazyInit();
		
		//如果没有数组,或设置成其他字符都会被设置成false---即默认都不是懒惰初始化的
		bd.setLazyInit(TRUE_VALUE.equals(lazyInit));
        
        //解析autowire属性  
		String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
		//设置自动注入模式--构造器注入,按照类型注入等
		bd.setAutowireMode(getAutowireMode(autowire));
          
          //解析depends-on属性 
		if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) 
			String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE);
			bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS));
		
         
         //解析autowire-candidate属性 
		String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE);
		if (isDefaultValue(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 Spring读源码系列番外篇---02---PropertyResolver的结构体系剖析---上

dubbo系列dubbo启动过程源码解析

3Spring 源码学习 ~ 默认标签的解析之 Bean 标签解析

Spring源码分析bean标签的解析及注册

Spring 源码分析--自定义标签的使用

Spring读源码系列之AOP--08--aop执行完整源码流程之自动代理创建器导入的两种方式