El archivo de configuración de Spring se carga como análisis del proceso BeanDefinition

1: escribe al frente

En el trabajo real, a menudo puedo escribir el siguiente código:

@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);
}

El contenido del archivo de configuración utilizado es el siguiente:

<?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>

Este fragmento de código carga la información del bean en el archivo de configuración como BeanDefinition en Spring, que es la estructura de datos que almacena la información del bean que definimos en Spring. La generación final de los beans Spring también depende de esta estructura de datos. El resultado final de ejecución del código es el siguiente:

bean定义的个数是:2

Lo que se devuelve es el número de beans definidos en el archivo de configuración.

2: loadBeanDefinitions

Este método completa la función de cargar beandefinition desde el recurso encapsulado con el archivo de configuración, la ubicación específica es la siguiente:

org.springframework.beans.factory.xml.XmlBeanDefinitionReader#loadBeanDefinitions(org.springframework.core.io.Resource)
@Override
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
    
    
	// 其中EncodedResource是加了编码的资源,不影响主流程,可以无视
	return loadBeanDefinitions(new EncodedResource(resource));
}

seguir adelante:

org.springframework.beans.factory.xml.XmlBeanDefinitionReader#loadBeanDefinitions(org.springframework.core.io.support.EncodedResource)
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
    
    
	// 断言判断传入的资源不为null
	Assert.notNull(encodedResource, "EncodedResource must not be null");
	if (logger.isTraceEnabled()) {
    
    
		logger.trace("Loading XML bean definitions from " + encodedResource);
	}
	// <2021-02-24 12:21>
	// 从resourcesCurrentlyBeingLoaded中获取当前线程已经或者是正在加载的资源集合
	Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
	// 如果是不存在已经加载的资源则创建,注意这里是
	// 使用的HashSet,因为资源不允许重复
	if (currentResources == null) {
    
    
		currentResources = new HashSet<>(4);
		// 存储新创建的资源到resourcesCurrentlyBeingLoaded中
		this.resourcesCurrentlyBeingLoaded.set(currentResources);
	}
	// <2021-02-24 12:23>
	// 这里如果是资源在set集合中已经存在会返回false,此时代表资源重复
	// 直接抛出BeanDefinitionStoreException信息
	if (!currentResources.add(encodedResource)) {
    
    
		throw new BeanDefinitionStoreException(
				"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
	}
	try {
    
    
		// 获取对应的资源,然后从资源中获取输入流
		InputStream inputStream = encodedResource.getResource().getInputStream();
		try {
    
    
			// 封装到InputSource中
			InputSource inputSource = new InputSource(inputStream);
			// 如果有编码则使用,不影响主流程,可以忽略
			if (encodedResource.getEncoding() != null) {
    
    
				inputSource.setEncoding(encodedResource.getEncoding());
			}
			// <2021-02-24 12:27>
			// 实现具体加载为BeanDefinition的过程
			return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
		}
		finally {
    
    
			inputStream.close();
		}
	}
	catch (IOException ex) {
    
    
		throw new BeanDefinitionStoreException(
				"IOException parsing XML document from " + encodedResource.getResource(), ex);
	}
	finally {
    
    
		// 删除资源
		currentResources.remove(encodedResource);
		// 如果删除当前资源后,没有其他资源,则清空threadlocal
		if (currentResources.isEmpty()) {
    
    
			this.resourcesCurrentlyBeingLoaded.remove();
		}
	}
}

<2021-02-24 12:21>La variable se define como private final ThreadLocal<Set<EncodedResource>> resourcesCurrentlyBeingLoaded = new NamedThreadLocal<>("XML bean definition resources currently being loaded");una subclase NamedThreadLocalde java.lang.ThreadLocalla clase, pero se agrega el atributo del nombre. El código fuente es el siguiente:

public class NamedThreadLocal<T> extends ThreadLocal<T> {
    
    

	private final String name;

	public NamedThreadLocal(String name) {
    
    
		Assert.hasText(name, "Name must not be empty");
		this.name = name;
	}

	@Override
	public String toString() {
    
    
		return this.name;
	}
}

<2021-02-24 12:23>El punto es juzgar si el recurso existe, principalmente para lidiar con la situación de presentarse uno mismo, de modo que ocurra un bucle infinito de introducción de recursos, entonces ocúpese de ello, la siguiente situación será un bucle infinito:
Inserte la descripción de la imagen aquí
pruebe y ejecute lo siguiente código:

@Test
public void testBeanDefinitionStoreException() {
    
    
    // 定义资源
    ClassPathResource classPathResource = new ClassPathResource("testbeandefinition.xml");
    // 定义IOC容器
    DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
    // 定义bean定义读取器
    XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(defaultListableBeanFactory);
    // 通过bean定义读取器从资源中读取bean定义
    xmlBeanDefinitionReader.loadBeanDefinitions(classPathResource);
}

Funcionamiento anormal: el
Inserte la descripción de la imagen aquí
<2021-02-24 12:27>código fuente es el siguiente:

org.springframework.beans.factory.xml.XmlBeanDefinitionReader#doLoadBeanDefinitions
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
			throws BeanDefinitionStoreException {
    
    
	try {
    
    
		// <2021-02-24 16:01> 获取xml文件对应的文档对象
		Document doc = doLoadDocument(inputSource, resource);
		// <2021-02-24 16:02> 根据文档对象注册Bean信息
		int count = registerBeanDefinitions(doc, resource);
		if (logger.isDebugEnabled()) {
    
    
			logger.debug("Loaded " + count + " bean definitions from " + resource);
		}
		return count;
	}
	catch (BeanDefinitionStoreException ex) {
    
    
		throw ex;
	}
	catch (SAXParseException ex) {
    
    
		...snip...
	}
	catch (SAXException ex) {
    
    
		...snip...
	}
	catch (ParserConfigurationException ex) {
    
    
		...snip...
	}
	catch (IOException ex) {
    
    
		...snip...
	}
	catch (Throwable ex) {
    
    
		...snip...
	}
}

<2021-02-24 16:01>El código fuente es el siguiente:

protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
    
    
	return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
			getValidationModeForResource(resource), isNamespaceAware());
}

El código getValidationModeForResource(resource)es para obtener el modelo de verificación, puede consultar aquí para obtener más detalles . El código this.documentLoader.loadDocumentes para obtener la instancia del documento correspondiente al archivo XML, para más detalles, consulte aquí . <2021-02-24 16:02>, Registre la información de BeanDefinition de acuerdo con la información del documento del documento, consulte aquí para obtener más detalles .

Supongo que te gusta

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