环境准备:

使用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 分析的更多相关文章

  1. Spring源码系列 — Bean生命周期

    前言 上篇文章中介绍了Spring容器的扩展点,这个是在Bean的创建过程之前执行的逻辑.承接扩展点之后,就是Spring容器的另一个核心:Bean的生命周期过程.这个生命周期过程大致经历了一下的几个 ...

  2. Ioc容器BeanPostProcessor-Spring 源码系列(3)

    Ioc容器BeanPostProcessor-Spring 源码系列(3) 目录: Ioc容器beanDefinition-Spring 源码(1) Ioc容器依赖注入-Spring 源码(2) Io ...

  3. Ioc容器beanDefinition-Spring 源码系列(1)

    Ioc容器beanDefinition-Spring 源码系列(1) 目录: Ioc容器beanDefinition-Spring 源码(1) Ioc容器依赖注入-Spring 源码(2) Ioc容器 ...

  4. AOP执行增强-Spring 源码系列(5)

    AOP增强实现-Spring 源码系列(5) 目录: Ioc容器beanDefinition-Spring 源码(1) Ioc容器依赖注入-Spring 源码(2) Ioc容器BeanPostProc ...

  5. Spring源码系列 — 注解原理

    前言 前文中主要介绍了Spring中处理BeanDefinition的扩展点,其中着重介绍BeanDefinitionParser方式的扩展.本篇文章承接该内容,详解Spring中如何利用BeanDe ...

  6. Spring源码系列 — BeanDefinition扩展点

    前言 前文介绍了Spring Bean的生命周期,也算是XML IOC系列的完结.但是Spring的博大精深,还有很多盲点需要摸索.整合前面的系列文章,从Resource到BeanDefinition ...

  7. Spring源码系列 — BeanDefinition

    一.前言 回顾 在Spring源码系列第二篇中介绍了Environment组件,后续又介绍Spring中Resource的抽象,但是对于上下文的启动过程详解并未继续.经过一个星期的准备,梳理了Spri ...

  8. 事件机制-Spring 源码系列(4)

    事件机制-Spring 源码系列(4) 目录: Ioc容器beanDefinition-Spring 源码(1) Ioc容器依赖注入-Spring 源码(2) Ioc容器BeanPostProcess ...

  9. Ioc容器依赖注入-Spring 源码系列(2)

    Ioc容器依赖注入-Spring 源码系列(2) 目录: Ioc容器beanDefinition-Spring 源码(1) Ioc容器依赖注入-Spring 源码(2) Ioc容器BeanPostPr ...

随机推荐

  1. TCP/IP||Traceroute

    1.概述 由Van jacobson编写的工具,用于探索tcp/ip协议,使用ICMP报文和首部TTL字段,TTL字段由发送端设置一个8bit字段,初始值为RFC指定,当前值为64, 每个处理数据的路 ...

  2. IntelliJ Idea中的 Facets 与 Artifacts

    在公司和家用电脑上不同版本的idea做实验发现过程中会有些不同,遇到过一些问题,也正是这些问题使得自己能更进一步了解项目构建过程中的细节,特别记录一下.   这个是[温故知新] Java web 开发 ...

  3. FPGA之IO信号类型深入理解

    在FPGA设计开发中,很多场合会遇到同一根信号既可以是输入信号,又可以是输出信号,即IO类型(Verilog定义成inout). 对于inout型的信号,我们既可以使用FPGA原语来实现,也可以使用V ...

  4. 图解leetcode279 —— 完全平方数

    每道题附带动态示意图,提供java.python两种语言答案,力求提供leetcode最优解. 描述: 给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...)使得它们的和等于  ...

  5. appium获取toast和操作webview实例

    从testerhome上看到很多测试同学分享了toast的获取方式,其中大部分是java版本的,但也有个python版本的:Appium1.7.2 android toast 消息测试 Appium获 ...

  6. HDU3652 B-number 题解 数位DP

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3652 题目大意: 求区间 \([1, n]\) 范围内包含连续的数位"13"并且能 ...

  7. 1038 统计同成绩学生 (20 分)C语言

    题目描述 本题要求读入N名学生的成绩,将获得某一给定分数的学生人数输出. 输入描述: 输入在第1行给出不超过105的正整数N,即学生总人数.随后1行给出N名学生的百分制整数成绩,中间以空格分隔.最后1 ...

  8. infer 代码静态分析

    infer 代码静态分析 静态代码分析工具,主要是为了提高我们的代码质量. 通常,我们提高代码质量的方式是通过CodeReview,但是这个过程耗费的人工和时间往往较大.并且随着代码量的增加人肉检测起 ...

  9. 1z0-062 题库解析5

    题目: Which three statements are true about Flashback Database? A. Flashback logs are written sequenti ...

  10. cannot mount volume over existing file, file exists /var/lib/docker/overlay2/.../merged/usr/share/zoneinfo/UTC 解决

    问题产生原因: linux系统docker-compose.yml文件 放到 mac本启动发现启动报错 cannot mount volume over existing file, file exi ...