IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Spring源码之bean的注册流程 -> 正文阅读

[Java知识库]Spring源码之bean的注册流程

为了更好的理解Spring中bean的注册原理,我们通过一个示例进行分析,代码如下:

public static void main(String[] args) {
	BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("spring-bean-test.xml"));
	MyBean bean = (MyBean) beanFactory.getBean("myBean");
	System.out.println("My name is : " + bean.getName());
}

其中配置文件如下(核心部分):

<beans>
	<bean id="myBean" class="com.bean.MyBean" />
</beans>

XmlBeanFactory简介

  1. XmlBeanFactory继承自DefaultLisableBeanFactory,DefaultLisableBeanFactory是整个bean加载的核心部分,XmlBeanFactory通过继承DefaultLisableBeanFactory的方式,实现了个性化的XML读取器BeanDefinitionReader,用来从XML配置中读取Bean的定义。
  2. 因为Spring的大部分功能是以配置作为切入点的,因此XML配置文件的读取是Spring源码中的重要一环。

XmlBeanFactory详解

首先来看第一段代码:

BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource(“spring-bean-test.xml”));

这个里面ClassPathResource这里就不说了,主要来看new XmlBeanFactory,这个类中有两个构造函数:

public class XmlBeanFactory extends DefaultListableBeanFactory {
	private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
	/**
	 * 这是第一个构造函数,这里会指定xml资源
	 */
	public XmlBeanFactory(Resource resource) throws BeansException {
		this(resource, null);
	}
	/**
	 * 这是第二个构造函数,指定的xml资源会通过loadBeanDefinitions进行读取
	 */
	public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
		super(parentBeanFactory);
		this.reader.loadBeanDefinitions(resource);
	}
}

通过源码可知,我们代码中的spring-bean-test.xml作为参数传给了XmlBeanDefinitionReader 类,通过这个类的loadBeanDefinitions方法进行读取,我们接着看loadBeanDefinitions,这个方法是整个xml资源加载的重要方法,这个方法里面的核心逻辑如下:

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
	// 省略部分非重点代码...
	InputStream inputStream = encodedResource.getResource().getInputStream();
	try {
		InputSource inputSource = new InputSource(inputStream);
		if (encodedResource.getEncoding() != null) {
			inputSource.setEncoding(encodedResource.getEncoding());
		}
		return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
	}finally {
		inputStream.close();
	}
	// 省略部分非重点代码...
}

从上面可以看到,核心的方法其实就是doLoadBeanDefinitions方法,这个方法如下:

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
		throws BeanDefinitionStoreException {
	try {
		int validationMode = getValidationModeForResource(resource);
		Document doc = this.documentLoader.loadDocument(
				inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
		return registerBeanDefinitions(doc, resource);
	}
	// 后面省略很多catch异常的语句

try中的语句很简单,主要就做了3件事:

  • 获取对xml文件的验证模式
  • 加载xml文件得到document对象
  • 根据得到的document对象进行bean注册

验证模式的获取这里暂不介绍,下面我们来看获取document的方法loadDocument,这里的documentLoader是一个接口类,真正调用的是它的实现类DefaultDocumentLoader,实现类中通过创建DocumentBuilderFactory来创建DocumentBuilder,进而解析inputSource来返回Document对象。

然后就是根据document来解析和注册bean的方法registerBeanDefinitions,源码如下:

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
	BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
	int countBefore = getRegistry().getBeanDefinitionCount();
	documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
	return getRegistry().getBeanDefinitionCount() - countBefore;
}

这个方法核心的逻辑就是通过创建BeanDefinitionDocumentReader来解析xml文件并进行bean的注册,这个BeanDefinitionDocumentReader也是一个接口类,实现类是DefaultBeanDefinitionDocumentReader,源码如下:

public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
	this.readerContext = readerContext;
	logger.debug("Loading bean definitions");
	Element root = doc.getDocumentElement();
	BeanDefinitionParserDelegate delegate = createHelper(readerContext, root);
	preProcessXml(root);
	parseBeanDefinitions(root, delegate);
	postProcessXml(root);
}

这个方法就是读取xml的root节点,通过parseBeanDefinitions来循环读取下面的子节点进行Bean的注册,其中preProcessXml,postProcessXml两个方法是预留的一个拓展点,可以在子类中实现这两个方法在注册bean之前和之后进行一些自定义的处理。

总结

通过parseBeanDefinitions将bean注册到容器中之后,通过下面的语句即可获得bean,并进行调用。

beanFactory.getBean(“myBean”)
System.out.println("My name is : " + bean.getName());

到此,bean的注册过程就全部完成了,这个是spring中默认的配置解析流程,对于parseBeanDefinitions中是如何详细进行xml各节点解析的,将在下篇文章中进行分享。

最后,欢迎大家指出文章中描述不详细的地方,后面我会持续根据大家的指正进行更新。

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-11-15 15:42:36  更:2021-11-15 15:44:41 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 2:50:08-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码