七、Spring MVC 源码学习(DefaultBeanDefinitionDocumentReader)

一、类职责

            解析dom中的import、alias元素,并委派(BeanDefinitionParserDelegate)处理beans、bean元素

二、主流程

———————————————————————————————-

           DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(Document doc, XmlReaderContext readerContext)

           1.获取文档根元素          //Element root = doc.getDocumentElement();

           2.创建BeanDefinitionParserDelegate ,该类具体处理文档中的

           3.排除掉Environment中不被接受地profile

           4.文档处理前的 前置处理(空实现,方便扩展)//preProcessXml()

           5.利用BeanDefinitionParserDelegate将文档解析为beanDefinition(下面进行具体分析)    //parseBeanDefinitions

           6.文档的后置处理(空实现,方便扩展)//postProcessXml();

protected void doRegisterBeanDefinitions(Element root) {
		// Any nested <beans> elements will cause recursion in this method. In
		// order to propagate and preserve <beans> default-* attributes correctly,
		// keep track of the current (parent) delegate, which may be null. Create
		// the new (child) delegate with a reference to the parent for fallback purposes,
		// then ultimately reset this.delegate back to its original (parent) reference.
		// this behavior emulates a stack of delegates without actually necessitating one.
		BeanDefinitionParserDelegate parent = this.delegate;
		this.delegate = createDelegate(getReaderContext(), root, parent);

		if (this.delegate.isDefaultNamespace(root)) {
			String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
			if (StringUtils.hasText(profileSpec)) {
				String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
						profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
				if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
					if (logger.isInfoEnabled()) {
						logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
								"] not matching: " + getReaderContext().getResource());
					}
					return;
				}
			}
		}

		preProcessXml(root);
		parseBeanDefinitions(root, this.delegate);
		postProcessXml(root);

		this.delegate = parent;
	}

———————————————————————————————–

 DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)

1.dom根元素是否存在于默认的命名空间中

          1.1 在命名空间中  执行后续步骤

          1.2 不在命名空间中,执行BeanDefinitionParserDelegate的定制处理(BeanDefinitionParserDelegate)

2.子元素是否存在于默认命名空间

          2.1  在命名空间中,执行parseDefaultElement(ele, delegate)//下面分析;

          2.2  不在命名空间中,执行BeanDefinitionParserDelegate的定制处理(BeanDefinitionParserDelegate)

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
		if (delegate.isDefaultNamespace(root)) {
			NodeList nl = root.getChildNodes();
			for (int i = 0; i < nl.getLength(); i++) {
				Node node = nl.item(i);
				if (node instanceof Element) {
					Element ele = (Element) node;
					if (delegate.isDefaultNamespace(ele)) {
						parseDefaultElement(ele, delegate);
					}
					else {
						delegate.parseCustomElement(ele);
					}
				}
			}
		}
		else {
			delegate.parseCustomElement(root);
		}
	}

———————————————————————————————————————–

DefaultBeanDefinitionDocumentReader.parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate)

 分别对import、beans、alias、bean元素做处理

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
		if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
			importBeanDefinitionResource(ele);
		}
		else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
			processAliasRegistration(ele);
		}
		else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
			processBeanDefinition(ele, delegate);
		}
		else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
			// recurse
			doRegisterBeanDefinitions(ele);
		}
	}

    下面我们着重分析processBeanDefinition的过程   

三、processBeanDefinition代码分析

1.把xml文档中的bean标签解析成BeanDefinitionHolder

                                                          实现由:BeanDefinitionParserDelegate.parseBeanDefinitionElement

2.对生成的BeanDefinitionHolder再次处理(针对以下两种情况)

      2.1(attr属性空间与bean空间不一致)

<!--外部命名空间为bean  内部却为p-->
<bean id="viewResolver" p:prefix="/WEB-INF/view/" p:suffix=".jsp"/>

      2.2(子标签内外空间不一致)

<bean>
        <!-- 外部为bean空间,内部为task空间-->
        <task:scheduler id=""/>
</bean>

调用BeanDefinitionParserDelegate.decorateIfRequired修饰处理

3.以beanName为K,以beanDefinition为V 存入beanFactory.beanDefinition

   以beanName为K,以alias为V 存入beanFactory.alias

4.触发组件注册事件(空实现)

四、补充

1.对import标签的解析

如下:

 <import resource="com/test/dao/dao-${test}.xml" />

源码如下:

protected void importBeanDefinitionResource(Element ele) {
		String location = ele.getAttribute(RESOURCE_ATTRIBUTE);
		// Resolve system properties: e.g. "${user.dir}"
		location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location);
}

分析:

        1.先读取到import标签中的resource属性

        2.使用Environment去替换${}代表的值

注:Environment中存储了系统属性(System.getProperty)和环境变量(System.getenv)

 

 

 

 

 

 

 

    原文作者:Spring Boot
    原文地址: https://blog.csdn.net/qq2413273056/article/details/82657766
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞