Análisis del proceso de etiquetas de importación de Spring Parsing

Escribir al frente

Este artículo continúa el análisis sobre la base de este artículo . Este artículo analiza principalmente el proceso de importación de archivos de configuración con la etiqueta de importación.

1: Rol

El desacoplamiento de los archivos de configuración reduce la complejidad de la escritura del archivo de configuración y el mantenimiento posterior.

2: código de prueba

Para facilitar la depuración y luego pegar el código de prueba:

@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 id="testBeanDefinitionBean1" class="yudaosourcecode.spring.TestBeanDefinitionBean"/>
    <import resource="needimported.xml"/>
</beans>

Introducido en el archivo de configuración needimported.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="testBeanDefinitionBean2" class="yudaosourcecode.spring.TestBeanDefinitionBean"/>
</beans>

Luego, org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#parseDefaultElementgolpee los siguientes puntos de interrupción, puede comenzar a depurar:
Inserte la descripción de la imagen aquí

3: importBeanDefinitionResource

Código fuente:

org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#importBeanDefinitionResource
protected void importBeanDefinitionResource(Element ele) {
    
    
	// 获取import标签的resource属性的值,即需要引入的配置文件的地址
	String location = ele.getAttribute(RESOURCE_ATTRIBUTE);
	// 如果是resource值为空,直接error,并return
	if (!StringUtils.hasText(location)) {
    
    
		getReaderContext().error("Resource location must not be empty", ele);
		return;
	}
	// <2021-03-01 10:54>
	// 解析系统环境变量
	location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location);
	// 最终需要加载的资源的集合
	Set<Resource> actualResources = new LinkedHashSet<>(4);
	// 是相对路径还是绝对路径?
	boolean absoluteLocation = false;
	try {
    
    
		// 1:classpath:,classpath*:是绝对路径
		// 2:能够构造url的是绝对路径,如file:/xxxx,http://,jar:// 等资源访问协议定义的路径
		absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute();
	}
	catch (URISyntaxException ex) {
    
    
		...snip...
	}

	// 如果是绝对路径,classpath:,classpath*:,file:/,http:等
	// 这里需要区分是相对路径还是绝对路径的原因是,递归加载
	// import资源使用的方式和API会有所不同
	if (absoluteLocation) {
    
    
		try {
    
    
			// 递归导入,注意这里调用的是loadBeanDefinition的另一个重载版本了,不过殊途同归
			int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources);
			if (logger.isTraceEnabled()) {
    
    
				logger.trace("Imported " + importCount + " bean definitions from URL location [" + location + "]");
			}
		}
		catch (BeanDefinitionStoreException ex) {
    
    
			getReaderContext().error(
					"Failed to import bean definitions from URL location [" + location + "]", ele, ex);
		}
	}
	// 如果是相对路径,非以classpath:,classpath*:,http://.file:/等开头的路径
	// 如果不是绝对路径则默认就是相对于当前资源的相对路径
	else {
    
    
		try {
    
    
			int importCount;
			// 根据当前资源(当前解析的import标签所在资源)的相对路径创建需要import的资源
			Resource relativeResource = getReaderContext().getResource().createRelative(location);
			// 需要import的相对路径资源存在
			if (relativeResource.exists()) {
    
    
				// 递归调用
				importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource);
				// 添加资源
				actualResources.add(relativeResource);
			}
			// 需要import的相对路径资源不存在,理论上相对不存在,这种方式也不会存在,不知道为啥还要执行后续操作
			else {
    
    
				// 获取当前资源基础路径,如file:/E:/workspace-idea/java-life/target/classes/testbeandefinition.xml
				String baseLocation = getReaderContext().getResource().getURL().toString();
				// <2021-03-01 11:32>
				importCount = getReaderContext().getReader().loadBeanDefinitions(
						StringUtils.applyRelativePath(baseLocation, location), actualResources);
			}
			if (logger.isTraceEnabled()) {
    
    
				logger.trace("Imported " + importCount + " bean definitions from relative location [" + location + "]");
			}
		}
		catch (IOException ex) {
    
    
			getReaderContext().error("Failed to resolve current resource location", ele, ex);
		}
		catch (BeanDefinitionStoreException ex) {
    
    
			getReaderContext().error(
					"Failed to import bean definitions from relative location [" + location + "]", ele, ex);
		}
	}
	// 加载到的资源转成数据,并触发导入已经处理事件
	Resource[] actResArray = actualResources.toArray(new Resource[0]);
	getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele));
}

<2021-03-01 10:54>Es para reemplazar las variables de entorno, como las siguientes variables de entorno:

C:\Users\Administrator>set
ALLUSERSPROFILE=C:\ProgramData
...snip...

Luego modifique el xml para <import resource="${ALLUSERSPROFILE}/needimported.xml"/>depurar allí, y el valor obtenido es el siguiente:
Inserte la descripción de la imagen aquí
Puede ver que el valor real de la variable de entorno ha sido reemplazado.
<2021-03-01 11:32>El punto es aplicar la ruta relativa basada en la ruta absoluta base para obtener la ruta absoluta de la ruta relativa. Si la ruta absoluta base es la file:/E:/workspace-idea/java-life/target/classes/testbeandefinition.xmlruta relativa needimported1.xml, el resultado es file:/E:/workspace-idea/java-life/target/classes/needimported1.xml.
Luego, veamos el proceso de análisis de la etiqueta del bean aquí , porque la etiqueta del bean se resolverá al final.

Supongo que te gusta

Origin blog.csdn.net/wang0907/article/details/114252284
Recomendado
Clasificación