Spring構成ファイルはBeanDefinitionプロセス分析としてロードされます

1:前に書く

実際の作業では、次のコードを書くことがよくあります。

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

このコードは、春にBeanDefinitionとして構成ファイルにBean情報をロードします。これは、Springで定義したBean情報を格納するデータ構造です。SpringBeanの最終生成も、このデータ構造に依存します。最終的な実行結果コードの内容は次のとおりです。

bean定义的个数是:2

返されるのは、構成ファイルで定義されているBeanの数です。

2:loadBeanDefinitions

このメソッドは、構成ファイルでカプセル化されたリソースからbeandefinitionをロードする機能を完了します。具体的な場所は次のとおりです。

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

続ける:

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>変数は以下のように定義されるprivate final ThreadLocal<Set<EncodedResource>> resourcesCurrentlyBeingLoaded = new NamedThreadLocal<>("XML bean definition resources currently being loaded");サブクラスNamedThreadLocaljava.lang.ThreadLocalクラスが、名前の属性が追加され、以下のようにソースコードがあります:

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>重要なのは、主に自己紹介の状況に対処するためにリソースが存在するかどうかを判断し、リソース導入の無限ループが発生するようにすることです。それに対処すると、次の状況は無限ループに
ここに画像の説明を挿入します
なります。次のテストを実行して実行します。コード:

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

異常動作:
ここに画像の説明を挿入します
<2021-02-24 12:27>ソースコードは次のとおりです。

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>ソースコードは次のとおりです。

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

コードgetValidationModeForResource(resource)は検証モデルを取得するためのものです詳細については、こちらを参照してくださいコードthis.documentLoader.loadDocumentは、XMLファイルに対応するDocumentインスタンスを取得するためのものです。詳細については、こちらを参照してください<2021-02-24 16:02>、ドキュメントドキュメント情報に従ってBeanDefinition情報を登録します詳細については、こちらを参照してください

おすすめ

転載: blog.csdn.net/wang0907/article/details/114016448