Spring通过Xml方式注册Bean的几处关键实现点
Posted 沉迷Spring
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring通过Xml方式注册Bean的几处关键实现点相关的知识,希望对你有一定的参考价值。
1.前言
我们用SpringMVC的时候一般会用到Xml配置文件,那么我们这篇文章就来谈下Spring读取Xml配置文件的一些关键实现点。
2.AbstractRefreshableApplicationContext
这个抽象类的名称告诉我们这是一个具备可刷新能力的应用上下文,并且里面定义了一个关键接口loadBeanDefinitions
:
/**
* Load bean definitions into the given bean factory, typically through
* delegating to one or more bean definition readers.
* @param beanFactory the bean factory to load bean definitions into
* @throws BeansException if parsing of the bean definitions failed
* @throws IOException if loading of bean definition files failed
* @see org.springframework.beans.factory.support.PropertiesBeanDefinitionReader
* @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
*/
protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
throws BeansException, IOException;
我们从这个接口名称就可以看出是用来加载BeanDefinition的,并且参数传入了一个很重要的东西BeanFactory,那么这个接口由谁来实现了呢?
2.AbstractXmlApplicationContext
/**
* Loads the bean definitions via an XmlBeanDefinitionReader.
* @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
* @see #initBeanDefinitionReader
* @see #loadBeanDefinitions
*/
//todo 重载了 AbstractRefreshableApplicationContext
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
//todo 传入bean工厂 使得beanDefinitionReader有了 Environment 2020-09-11
//todo 使得beanDefinitionReader有了 BeanRegistry 2020-09-11
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// Configure the bean definition reader with this context's
// resource loading environment.
//todo beanDefinitionReader 又设置了 Environment 把当前Context的环境 给了他 2020-09-11
beanDefinitionReader.setEnvironment(this.getEnvironment());
//todo important 设置为ClassPathXmlApplicationContext 又因为AbstractApplicationContext继承自 DefaultResourceLoader 为自己 2020-08-31
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// Allow a subclass to provide custom initialization of the reader,
// then proceed with actually loading the bean definitions.
//初始化beanReader
initBeanDefinitionReader(beanDefinitionReader);
//加载bean定义
loadBeanDefinitions(beanDefinitionReader);
}
这个loadBeanDefinitions接口的实现做了几件事情,我们来分析下:1.每次调用都会实例化一个XmlBeanDefinitionReader
对象,并且把接口的参数beanFactory都放入了它的构造函数。我们看XmlBeanDefinitionReader
类的构造函数实际上是接收一个BeanDefinitionRegistry接口的,也就是说DefaultListableBeanFactory实现了BeanDefinitionRegistry接口,这个实现就为之后解析Bean配置并且用通过这个registry注册BeanDefinition提供了可能。至于BeanDefinitionRegistry接口我们可以之后单独写文来分析,在这里就不展开讨论。2.把当前应用上下文的Envrionment环境给了XmlBeanDefinitionReader,这点也很重要,我们还记得可以在Xml配置文件中定义bean的profile配置来开发环境来筛选吗?我们来截张图:看红圈圈出来的地方,beanDefinitionReader.setEnvironment就让这个功能实现得到了基础保障,因为我们肯定首先要有应用上下文的环境嘛,具体这个profile小配置的解析之后我们用个简短的小文章来揭秘下。3.设置了beanDefinitionReader的ResourceLoader为当前应用上下文。4.设置了entityResolver,先不管。5.初始化了beanDefinitionReader,默认设置了下验证模式,先不用管。6.开始加载beanDefinitions,很重要。
最后一步最终调用到了beanDefinitionReader的registerBeanDefinitions这个方法。
3.XmlBeanDefinitionReader
/**
* Register the bean definitions contained in the given DOM document.
* Called by {@code loadBeanDefinitions}.
* <p>Creates a new instance of the parser class and invokes
* {@code registerBeanDefinitions} on it.
* @param doc the DOM document
* @param resource the resource descriptor (for context information)
* @return the number of bean definitions found
* @throws BeanDefinitionStoreException in case of parsing errors
* @see #loadBeanDefinitions
* @see #setDocumentReaderClass
* @see BeanDefinitionDocumentReader#registerBeanDefinitions
*/
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
//默认是DefaultBeanDefinitionDocumentReader
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
int countBefore = getRegistry().getBeanDefinitionCount();
//https://www.cnblogs.com/whx7762/p/7777775.html
//todo 里面最终调用了registry.registerBeanDefinition 2020-08-31
//todo createReaderContext new 一个XmlReaderContext 构造函数会传入 当前 XmlBeanDefinitionReader(继承自 AbstractBeanDefinitionReader 实现了 EnvironmentCapable 接口) 所以有了 Environment 2020-10-18
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
每次调用都会创建一个BeanDefinitionDocumentReader对象,默认就是在XmlBeanDefinitionReader中定义好的DefaultBeanDefinitionDocumentReader类。
获取registry中的BeanDefinition数量。
来来来!最重要一步就是通过创建的documentReader对象来注册beanDefinition了,传入了要解析的文档, 创建带有resource资源的readerContext给到我们的documentReader对象。
返回注册过后当前的beanDefinitionCount。
以上是关于Spring通过Xml方式注册Bean的几处关键实现点的主要内容,如果未能解决你的问题,请参考以下文章