spring源码系列(十): 读取xml入口类 ClassPathXmlApplicationContext 分析
环境准备:
使用spring5.1.6版本

1 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="user" class="com.hou.spring.bean.User"></bean>
</beans>
2 测试类
public class BeanTest{
@Test
public void beanTest(){
//spring4之后XmlBeanFactory被废弃,改用以下方式
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-bean.xml");
User user = (User) applicationContext.getBean("user");
System.out.println(user);
}
}
然后点进去源码,跟着一步步debug来分析:
1 构造器调用:
ClassPathXmlApplicationContext的构造器中调用类同名方法:

点击this跳转到初始化方法:

2 super()方法是一直到父类AbstractApplicationContext中,将ApplicationContext的环境属性设置给本类的环境属性,包括一些profile,系统属性等

3 setConfigLocations方法也是调用父类方法,将xml配置文件名字设置给父类的String数组属性

4 refresh() 方法,所有的逻辑其实都在这个方法里面进行,主要分析这个方法:

5 prepareRefresh主要还是环境属性的一些初始化,主要看第二步:
// Tell the subclass to refresh the internal bean factory. 告诉子类刷新内部bean工厂
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
点进去obtainFreshBeanFactory:

6 首先看refreshBeanFactory方法,注意,如果不知道是哪个子类的话,可以跟着debug断点走:

主要分为这么几个步骤:
一 首先判断本类的DefaultListableBeanFactory属性是否为null,如果不为null,就先清除一写跟Bean有关的Map或者List等属性集合
二 将BeanFactory设置为null,序列化id设置为null,
三 创建DefaultListableBeanFactory,这个类很重要,是springBean初始化的核心类,
四 对beanFactory进行设置,bean注册等操作,最后将beanFactory赋值给本类的beanFactory属性
7 customizeBeanFactory(beanFactory); 只做了两件事:

8 loadBeanDefinitions: Bean的注册主要是在这一步进行,下面进行分析,这个方法有5个子类实现:

我写的测试类不是Web项目,所以会进入AbstractXmlApplicationContext这个类里的方法,如果是Web项目,会走XmlWebApplicationContext:

首先创建XmlBeanDefinitionReader:xml配置读写器然后设置环境属性以及资源加载器为ClassPathXmlApplicationContext,这个加载器很重要,后面会用到
接着初始化读取器: initBeanDefinitionReader,最后加载Bean
8 initBeanDefinitionReader
这个方法默认实现是空的,允许用户自定义实现读取器的定制化,需要实现接口,可以设置xml解析完成校验,定制化解析器等
9 loadBeanDefinitions: 加载Bean信息,点进去:

这个方法主要是加载类的两个资源属性,Resource[] 和xml位置信息,主要看加载Xml的:
10 reader.loadBeanDefinitions(configLocations);

循环加载xml文件的Bean返回Bean总个数,查看加载方法:
11 查看这个load方法:

这里需要注意第八步设置的加载器,查看加载器的时序图:

因为有继承关系所以直接进if分支,继续分析if分支代码:

主要步骤:
1 获取加载器中的Resource[] 数组
2 加载资源中的Bean,返回加载数量
12 查看loadBeanDefinitions,循环加载了所有的资源,返回总数

13 查看单个加载方法loadBeanDefinitions,主要看中间一段逻辑:

这里对正在解析的xml资源放入ThreadLocal中,保证只有本次线程可以访问,加载完之后再移除
13 查看doLoadBeanDefinitions(inputSource, encodedResource.getResource());

spring源码系列(十): 读取xml入口类 ClassPathXmlApplicationContext 分析的更多相关文章
- Spring源码系列 — Bean生命周期
前言 上篇文章中介绍了Spring容器的扩展点,这个是在Bean的创建过程之前执行的逻辑.承接扩展点之后,就是Spring容器的另一个核心:Bean的生命周期过程.这个生命周期过程大致经历了一下的几个 ...
- Ioc容器BeanPostProcessor-Spring 源码系列(3)
Ioc容器BeanPostProcessor-Spring 源码系列(3) 目录: Ioc容器beanDefinition-Spring 源码(1) Ioc容器依赖注入-Spring 源码(2) Io ...
- Ioc容器beanDefinition-Spring 源码系列(1)
Ioc容器beanDefinition-Spring 源码系列(1) 目录: Ioc容器beanDefinition-Spring 源码(1) Ioc容器依赖注入-Spring 源码(2) Ioc容器 ...
- AOP执行增强-Spring 源码系列(5)
AOP增强实现-Spring 源码系列(5) 目录: Ioc容器beanDefinition-Spring 源码(1) Ioc容器依赖注入-Spring 源码(2) Ioc容器BeanPostProc ...
- Spring源码系列 — 注解原理
前言 前文中主要介绍了Spring中处理BeanDefinition的扩展点,其中着重介绍BeanDefinitionParser方式的扩展.本篇文章承接该内容,详解Spring中如何利用BeanDe ...
- Spring源码系列 — BeanDefinition扩展点
前言 前文介绍了Spring Bean的生命周期,也算是XML IOC系列的完结.但是Spring的博大精深,还有很多盲点需要摸索.整合前面的系列文章,从Resource到BeanDefinition ...
- Spring源码系列 — BeanDefinition
一.前言 回顾 在Spring源码系列第二篇中介绍了Environment组件,后续又介绍Spring中Resource的抽象,但是对于上下文的启动过程详解并未继续.经过一个星期的准备,梳理了Spri ...
- 事件机制-Spring 源码系列(4)
事件机制-Spring 源码系列(4) 目录: Ioc容器beanDefinition-Spring 源码(1) Ioc容器依赖注入-Spring 源码(2) Ioc容器BeanPostProcess ...
- Ioc容器依赖注入-Spring 源码系列(2)
Ioc容器依赖注入-Spring 源码系列(2) 目录: Ioc容器beanDefinition-Spring 源码(1) Ioc容器依赖注入-Spring 源码(2) Ioc容器BeanPostPr ...
随机推荐
- [Vue源码]一起来学Vue模板编译原理(二)-AST生成Render字符串
本文我们一起通过学习Vue模板编译原理(二)-AST生成Render字符串来分析Vue源码.预计接下来会围绕Vue源码来整理一些文章,如下. 一起来学Vue双向绑定原理-数据劫持和发布订阅 一起来学V ...
- eclipse中部署web项目时报错java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener的解决方法
解决方案: 1.右键点击项目--选择Properties,选择Deployment Assembly,在右边点击Add按钮,在弹出的窗口中选择Java Build Path Entries 2.点击N ...
- 014 Ceph管理和自定义CRUSHMAP
一.概念 1.1 Ceph集群写操作流程 client首先访问ceph monitor获取cluster map的一个副本,知晓集群的状态和配置 数据被转化为一个或多个对象,每个对象都具有对象名称和存 ...
- 005jz2440开发板恢复出厂系统
- 【汇编】AX内容依次倒排序
;P99,5.13,ax内容倒序 ;思路,ax左移一位最高位进cf里,bx右移一位把cf里值进bx的最高位, ;循环16次即实现ax16位内容倒序存储在bx中 DATA SEGMENT DATA EN ...
- 大白话抽象工厂模式(Abstract Factory Pattern)
实例分析 大白话工厂方法模式(Factory Method)一文中,我们讲解了日产4S店工厂规模的扩大,创建了针对不同车型的工厂,减少了工厂的工作内容,提高了效率.下面我们继续以4S店的故事讨论抽象工 ...
- HDU4352 XHXJ's LIS 题解 数位DP
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4352 题目大意: 求区间 \([L,R]\) 范围内最长上升子序列(Longest increasin ...
- Go数组和切片你不知道的区别
开篇语 数组和切片是两种不同的数据结构,比较常见,在Go语言中同时存在,今天我们就一起来看看他们在使用方式上,原理上的一些区别? 数组 在Go语言中,数组是一种具有相同类型固定大小的一种数据结构. 我 ...
- asp.net core系列 74 Exceptionless服务端安装
一. Docker安装 Docker 要求版本Docker 18.09.0+以上 安装地址:https://www.runoob.com/docker/windows-docker-insta ...
- vscode中nodejs智能提示
简单粗暴,直接在项目中,运行npm install --save-dev @types/node命令,然后就ok了.