spring将Document解析为BeanDefinition

写在前面

这篇文章中分析了从xml文件解析为Document文档的过程,在这篇文章我们来继续分析从Document解析为BeanDefinition的过程。

1:作用

加载xml数据结构为spring中的BeanDefinition数据结构,为生成spring bean做准备。

2:测试代码

为了方便调试再贴下测试代码:

@Test
public void testBeanDefinitionLoad() {
    
    
    // 定义资源
    ClassPathResource classPathResource = new ClassPathResource("testbeandefinition.xml");
    // 定义IOC容器
    DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
    // 定义bean定义读取器
    XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(defaultListableBeanFactory);
    // 通过bean定义读取器从资源中读取bean定义
    int i = xmlBeanDefinitionReader.loadBeanDefinitions(classPathResource);
    System.out.println("bean定义的个数是:" + i);
}

xml:

<?xml version="1.0" encoding="UTF-8"?>
<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">

    <bean id="testBeanDefinitionBean"
          class="yudaosourcecode.spring.TestBeanDefinitionBean"></bean>

    <bean id="testBeanDefinitionBean1"
          class="yudaosourcecode.spring.TestBeanDefinitionBean"></bean>
    <!-- 这里引入自己的话会发生org.springframework.beans.factory.BeanDefinitionStoreException异常 -->
    <!--<import resource="testbeandefinition.xml"/>-->
</beans>

执行测试代码,会执行到如下代码:

org.springframework.beans.factory.xml.XmlBeanDefinitionReader#registerBeanDefinitions
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
    
    
	// 创建bean定义文档读取器
	BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
	// 已经存在的BeanDefinition的个数
	int countBefore = getRegistry().getBeanDefinitionCount();
	// 使用documentReader通过document注册BeanDefinition
	documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
	// 当前的BeanDefinition的个数减去之前存在的个数,就是新增的个数
	return getRegistry().getBeanDefinitionCount() - countBefore;
}

3:createReaderContext

源码:

org.springframework.beans.factory.xml.XmlBeanDefinitionReader#createReaderContext
public XmlReaderContext createReaderContext(Resource resource) {
    
    
	return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
			this.sourceExtractor, this, getNamespaceHandlerResolver());
}

先不深究。

4:createBeanDefinitionDocumentReader

源码:

org.springframework.beans.factory.xml.XmlBeanDefinitionReader#createBeanDefinitionDocumentReader
protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {
    
    
	// 	private Class<? extends BeanDefinitionDocumentReader> documentReaderClass =
    // DefaultBeanDefinitionDocumentReader.class;
	return BeanUtils.instantiateClass(this.documentReaderClass);
}

DefaultBeanDefinitionDocumentReader是BeanDefinitionDocumentReader接口的实现类,完成从文档对象中注册BeanDefinition的功能。

5:registerBeanDefinitions

通过调用方法org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#registerBeanDefinitions完成注册BeanDefinition的功能,源码如下:

org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#registerBeanDefinitions
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
    
    
	this.readerContext = readerContext;
	// 调用doRegisterBeanDefinitions并获取根元素作为参数,这里是<beans>元素
	doRegisterBeanDefinitions(doc.getDocumentElement());
}

继续看源码:

org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions
protected void doRegisterBeanDefinitions(Element root) {
    
    
	BeanDefinitionParserDelegate parent = this.delegate;
	// <2021-02-28 05:52>
	this.delegate = createDelegate(getReaderContext(), root, parent);
	// <2021-02-28 05:53>
	// 获取是否为根元素,其实就是判断命名空间值为http://www.springframework.org/schema/beans/
	if (this.delegate.isDefaultNamespace(root)) {
    
    
		// 获取profiles属性的值,profile是用来设置生效的环境变量的
		// 和spring.active.profiles,spring.active.default配套
		// 使用的,一般为空,如果是配置了则进一步判断是否满足环境变量
		// 要求,如果是不满足则不加载,满足则继续
		String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
		// 配置了profile
		if (StringUtils.hasText(profileSpec)) {
    
    
			// 获取配置的profile信息
			String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
					profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
			// 如果是环境变量中设置的spring.active.prifle,或者是
			// spring.active.default和当前根元素中设置的相同则不return,然后继续加载工作,否则return
			if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
    
    
				if (logger.isDebugEnabled()) {
    
    
					logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
							"] not matching: " + getReaderContext().getResource());
				}
				return;
			}
		}
	}
	// 解析前处理,目前为空方法,留给子类扩展使用
	preProcessXml(root);
	// <2021-02-28 07:16>
	// 解析
	parseBeanDefinitions(root, this.delegate);
	// 解析后处理,目前是空方法,留给子类扩展使用
	postProcessXml(root);

	this.delegate = parent;
}

<2021-02-28 05:53>是处理profile信息的,如果是配置的profile在环境变量中没有设置,则不加载,如下xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans profile="gagagagaga" 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">

    <bean id="testBeanDefinitionBean"
          class="yudaosourcecode.spring.TestBeanDefinitionBean"></bean>

    <bean id="testBeanDefinitionBean1"
          class="yudaosourcecode.spring.TestBeanDefinitionBean"></bean>
    <!-- 这里引入自己的话会发生org.springframework.beans.factory.BeanDefinitionStoreException异常 -->
    <!--<import resource="testbeandefinition.xml"/>-->
</beans>

在根标签<beans>中设置了profile="gagagagaga",如下的测试代码注释了设置对应配套环境变量的代码,因此不会加载bean:

@Test
public void testBeanDefinitionLoad() {
    
    
    // System.setProperty("spring.profiles.active", "gagagagaga");
    // 定义资源
    ClassPathResource classPathResource = new ClassPathResource("testbeandefinition.xml");
    // 定义IOC容器
    DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
    // 定义bean定义读取器
    XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(defaultListableBeanFactory);
    // 通过bean定义读取器从资源中读取bean定义
    int i = xmlBeanDefinitionReader.loadBeanDefinitions(classPathResource);
    System.out.println("bean定义的个数是:" + i);
}

注意到其中的代码System.setProperty("spring.profiles.active", "gagagagaga");是注释掉的,运行debug,会进入到return:
在这里插入图片描述
运行可以看到加载的BeanDefinition的个数为0:

bean定义的个数是:0

如果把注释代码System.setProperty("spring.profiles.active", "gagagagaga");放开则就可以正常加载了,运行:

bean定义的个数是:2

<2021-02-28 05:52>处代码获取BeanDefinitionParserDelegate对象,该对象比较重要,负责解析工作。<2021-02-28 07:16>处源码如下:

org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#parseBeanDefinitions
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
    
    
	// 如果是默认命名空间,即命名空间为http://www.springframework.org/schema/beans/
	if (delegate.isDefaultNamespace(root)) {
    
    
		// 获取所有的子节点
		NodeList nl = root.getChildNodes();
		// 遍历所有的子节点
		for (int i = 0; i < nl.getLength(); i++) {
    
    
			Node node = nl.item(i);
			// 如果是Element类型
			if (node instanceof Element) {
    
    
				// 强转为Element
				Element ele = (Element) node;
				// 如果是默认命名空间标签,即值为
				// http://www.springframework.org/schema/beans/
				if (delegate.isDefaultNamespace(ele)) {
    
    
					// <2021-02-28 07:41>
					parseDefaultElement(ele, delegate);
				}
				else {
    
    
					// 处理非默认命名空间标签
					delegate.parseCustomElement(ele);
				}
			}
		}
	}
	else {
    
    
		// 处理非默认命名空间标签
		delegate.parseCustomElement(root);
	}
}

<2021-02-28 07:41>处代码解析默认元素,源码如下:

org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#parseDefaultElement
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
    
    
	// 如果是import标签
	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)) {
    
    
		// recurse
		doRegisterBeanDefinitions(ele);
	}
}

关于bean标签的解析可以参考这里,关于import标签的解析可以参考这里

猜你喜欢

转载自blog.csdn.net/wang0907/article/details/114218666