四、Spring默认标签之bean标签的解析及注册

一、先期准备

参见 三、Spring之解析及注册 BeanDefinitions 之默认标签的解析

二、bean 标签的解析及注册

(一)调用流程

  1. 首先委托 BeanDefinitionParserDelegate 类的 parseBeanDefinitionElement() 方法进行元素解析,返回 BeanDefinitionHolder 类型的实例 bdHolder,经过这个方法以后,bdHolder 实例已经包含我们配置文件中配置的各种属性了,例如 class、name、id、alias 之类的属性
  2. 当返回的 bdHolder 不为空的情况下若存在默认标签的子节点下再有自定义属性,还需要再次对自定义标签进行解析
  3. 解析完成以后,需要对解析后的 bdHolder 进行注册,同样,注册委托给了 BeanDefinitionReaderUtilsregisterBeanDefinition() 方法
  4. 最后发出响应事件,通知相关的监听器,这个 bean 已经加载完成
	protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
		/*
		 *    首先委托 BeanDefinitionParserDelegate 类的 parseBeanDefinitionElement() 方法进行元素解析,返回
		 * BeanDefinitionHolder 类型的实例 bdHolder,经过这个方法以后,bdHolder 实例已经包含我们配置文件中配
		 * 置的各种属性了,例如 class、name、id、alias 之类的属性
		 */
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
		if (bdHolder != null) {
			/*
			 *     当返回的 bdHolder 不为空的情况下若存在默认标签的子节点下再有自定义属性,还需要再次对自定义标签进行
			 * 解析
			 */
			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
			try {
				// Register the final decorated instance.
				/*
				 *     解析完成以后,需要对解析后的 bdHolder 进行注册,同样,注册委托给了 BeanDefinitionReaderUtils 的
				 * registerBeanDefinition() 方法
				 */
				BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
			}
			catch (BeanDefinitionStoreException ex) {
				getReaderContext().error("Failed to register bean definition with name '" +
						bdHolder.getBeanName() + "'", ele, ex);
			}
			// Send registration event.
			/*
			 *     最后发出响应事件,通知相关的监听器,这个 bean 已经加载完成
			 */
			getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
		}
	}
  • BeanDefinitionParserDelegate#parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean)
  1. 抽取元素中的 id 以及 name 属性
  2. 进一步解析其他所有属性并统一封装至 GenericBeanDefinition 类型的实例中
  3. 如果检测到 bean 没有指定 beanName,那么使用默认规则为此 Bean 生成 beanName
  4. 将获取到的信息封装到 BeanDefinitionHolder
	/**
	 * 主要是对属性 id 以及 name 的解析:
	 * 1.抽取元素中的 id 以及 name 属性
	 * 2.进一步解析其他所有属性并统一封装至 GenericBeanDefinition 类型的实例中
	 * 3.如果检测到 bean 没有指定 beanName,那么使用默认规则为此 Bean 生成 beanName
	 * 4.将获取到的信息封装到 BeanDefinitionHolder 中
	 */
	@Nullable
	public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
		// 解析 id 属性
		String id = ele.getAttribute(ID_ATTRIBUTE);
		// 解析 name 属性
		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));
		}

		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) {
			checkNameUniqueness(beanName, aliases, ele);
		}
		// 解析其他所有子元素,诸如:meta、lookup-method、replaced-method、constructor-arg、property、qualifier
		AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);

		if (beanDefinition != null) {
			// 若不存在 beanName 那么根据 Spring 中提供的命名规则为当前 bean 生成对应的 beanName
			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;
	}
  • BeanDefinitionParserDelegate#parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean)
  1. 创建用于承载属性的 AbstractBeanDefinition 类型的 GenericBeanDefinition
  2. 硬编码解析默认 <bean> 标签的各种属性
  3. 解析子元素 meta
  4. 解析子元素 lookup-method
  5. 解析子元素 replaced-method
  6. 解析子元素 constructor-arg
  7. 解析子元素 property
  8. 解析子元素 qualifier

	@Nullable
	public AbstractBeanDefinition parseBeanDefinitionElement(
			Element ele, String beanName, @Nullable BeanDefinition containingBean) {

		this.parseState.push(new BeanEntry(beanName));

		String className = null;
		// 解析 class 属性
		if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
			className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
		}
		String parent = null;
		// 解析 parent 属性
		if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
			parent = ele.getAttribute(PARENT_ATTRIBUTE);
		}

		try {
			/*
			 * 创建用于承载属性的 AbstractBeanDefinition 类型的 GenericBeanDefinition:
			 *     BeanDefinition 是一个接口,在 Spring 中存在三种实现:RootBeanDefinition、ChildBeanDefinition 以及
			 * GenericBeanDefinition 。三种实现均继承了 AbstractBeanDefinition ,其中 BeanDefinition 是配置文件 <bean>
			 * 元素标签在容器中的内部表现形式。<bean> 元素标签拥有 class、scope、lazy-init 等配置属性,BeanDefinition则
			 * 提供了相应的 beanClass、scope、lazyInit 属性,BeanDefinition 和 <bean> 中的属性是一一对应的。
			 */
			AbstractBeanDefinition bd = createBeanDefinition(className, parent);
			// 硬编码解析默认 <bean>标签的各种属性
			parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
			// 提取 description
			bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));

			//解析元数据
			parseMetaElements(ele, bd);
			/*
			 * 解析 lookup-method 属性:
			 *     我们通常称 lookup-method 为获取器注入,获取注入是一种特殊的方法注入,它是把一个方法声明为返回某种类型
			 * 的 bean,但实际要返回的 bean 是在配置文件里面配置的,此方法可用在设计有些可插拔的功能上,解除程序依赖。
			 * 案例参见书本 P53-54
			 */
			parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
			/*
			 * 解析 replaced-method 属性:
			 *     方法替换:可以在运行时用心得的方法替换现有的方法。与之前的 look-up 不同的是,replaced-method 不但可以
			 * 动态地替换返回实体 bean,而且还能动态地更改原有方法的逻辑。案例参见书本 P55-56
			 */
			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(@Nullable String className, @Nullable String parentName)
	/*
	 * 创建用于承载属性的 AbstractBeanDefinition 类型的 GenericBeanDefinition:
	 *     BeanDefinition 是一个接口,在 Spring 中存在三种实现:RootBeanDefinition、ChildBeanDefinition 以及
	 * GenericBeanDefinition 。三种实现均继承了 AbstractBeanDefinition ,其中 BeanDefinition 是配置文件 <bean>
	 * 元素标签在容器中的内部表现形式。<bean> 元素标签拥有 class、scope、lazy-init 等配置属性,BeanDefinition则
	 * 提供了相应的 beanClass、scope、lazyInit 属性,BeanDefinition 和 <bean> 中的属性是一一对应的。
	 */
	public static AbstractBeanDefinition createBeanDefinition(
			@Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException {

		GenericBeanDefinition bd = new GenericBeanDefinition();
		bd.setParentName(parentName);
		if (className != null) {
			if (classLoader != null) {
				// 若 classLoader 不为空,则使用已传入的 classLoader 同一虚拟机加载类对象,否则只是记录 className
				bd.setBeanClass(ClassUtils.forName(className, classLoader));
			}
			else {
				bd.setBeanClassName(className);
			}
		}
		return bd;
	}
  • BeanDefinitionParserDelegate#parseBeanDefinitionAttributes(Element ele, String beanName,@Nullable BeanDefinition containingBean, AbstractBeanDefinition bd)
	/**
	 * 对 <bean> 标签的所有属性进行解析,例如:scope、lazy-init 等
	 * 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) {

		if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
			// singleton 属性已不再使用,改为 scope 属性
			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) {
			// Take default from containing bean in case of an inner bean definition.
			// 在嵌入 BeanDefinition 情况下且没有单独指定 scope 属性则使用父类默认的属性
			bd.setScope(containingBean.getScope());
		}

		// 解析 abstract 属性
		if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {
			bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
		}

		// 解析 lazy-init 属性,若没有设置或者设置成其他字符都会被设置为 false
		String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
		if (isDefaultValue(lazyInit)) {
			lazyInit = this.defaults.getLazyInit();
		}
		bd.setLazyInit(TRUE_VALUE.equals(lazyInit));

		// 解析 autowire 属性
		String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
		bd.setAutowireMode(getAutowireMode(autowire));

		// 解析 depends-on 属性(depends-on用来指定Bean初始化及销毁时的顺序)
		if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) {
			String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE);
			bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS));
		}

		/*
		 * 解析 autowire-candidate 属性:
		 *     自动依赖注入大大简化了我们的工作量,但是也有缺陷,如果一个接口有多个实现类,我们该注入哪一个呢?
		 *     一种方法是设置其中一个bean不参与自动注入:<bean class="shangbo.spring.example38.MessageServiceDBImpl" autowire-candidate="false" />
		 *     另一种方法是全局设定哪些对象不参数自动注入:
		 *     <beans xmlns="http://www.springframework.org/schema/beans"
    			xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    			xsi:schemaLocation="http://www.springframework.org/schema/beans
				http://www.springframework.org/schema/beans/spring-beans.xsd"
				default-autowire="byType"
				default-autowire-candidates="messageServiceDBImpl">
		 */
		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 属性(相当于 @PostConstruct 注解)
		if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) {
			String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE);
			bd.setInitMethodName(initMethodName);
		}
		else if (this.defaults.getInitMethod() != null) {
			bd.setInitMethodName(this.defaults.getInitMethod());
			bd.setEnforceInitMethod(false);
		}

		// 解析 destroy-method 属性(相当于 @PreDestroy 注解)
		if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) {
			String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE);
			bd.setDestroyMethodName(destroyMethodName);
		}
		else if (this.defaults.getDestroyMethod() != null) {
			bd.setDestroyMethodName(this.defaults.getDestroyMethod());
			bd.setEnforceDestroyMethod(false);
		}

		// 解析 factory-method 属性(详情解析参见:https://blog.csdn.net/qq_33188563/article/details/82865165)
		if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) {
			bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE));
		}
		// 解析 factory-bean 属性(详情解析参见:https://blog.csdn.net/qq_33188563/article/details/82865165)
		if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {
			bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE));
		}

		return bd;
	}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章