回顾Bean与BeanDefinition的关系. BeanFactory容器. ApplicationContext上下文.

首先总结下:

  1. 开发人员定义Bean信息:分为XML形式定义;注解式定义
  2. ApplicationContext搜集Bean的定义;存储到BeabFactory容器的中。
  3. BeanFactory根据这些BeanDefinition创建Bean.缓存起来供我们使用。

[开发人员]--标注-->[Bean定义] ---搜集 -->[BeanDefinition]---创建-->[Bean]

此节:我们从代码层面分析此过程.

refresh()

refresh()方法描述了ApplicationContext的初始化过程,这个过程大部分工作都是执行Bean定义到BeanDefinition到Bean的过程。

refresh()大致可以分为五部分来看:

1.BeanDefinition入库前准备阶段

  • prepareRefresh();:主要工作环境属性的初始化,校验。
  • obtainFreshBeanFactory();: 准备一个beanFactory()(注:XML配置形式的Bean大多在此时执行了搜集入库)
  • prepareBeanFactory(beanFactory);:配置beanFactory的相关信息,包括类加载;类加载器,解析器,需要的依赖和需要忽略的依赖,早期的Bean级别后处理器,创建环境相关Bean
  • postProcessBeanFactory(beanFactory); 该方法只要是针对web类型的上下文中的增加配置beanFactory的相关属性。

总的的来说,此阶段是在做beanFactory的相关配置。

2.BeanDefinition搜集入库阶段

  • invokeBeanFactoryPostProcessors(beanFactory):此方法主要了搜集注解型BeanDefinition,注册这些BeanDefinition, 执行BeanFactoryPostProcessor.postProcessBeanFactory()方法,做入库时的修改操作。

此过程非常的精妙。由PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors()全全负责,
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors()方法上本质就干了两件事

  1. 执行注册型BeanFactoryPostProcessor:此时有个重要的ConfigurationClassPostProcessor注册器,此类会将注解配置型的BeanDefinition找到,并注册到BeanFactory中。
  2. 执行普通类型的BeanFactoryPostProcessor:做入库的修改操作。

3.部分特殊功能的Bean提前创建
此阶段把少部分特殊用处的BeanDefinition先创建Bean供使用。

  • registerBeanPostProcessors(beanFactory);实例化一些BeanPostProcessor为将来的BeanDefinition生成Bean时做准备。。
  • initMessageSource(); 初始化ApplicationContext的国际化相关组件Bean,消息绑定,消息解析
  • initApplicationEventMulticaster();:初始化广播器组件Bean,用于初始化过程中广播阶段性事件。
  • onRefresh(); 初始化子类中特殊Beans(也算是一个扩展点)
  • registerListeners();:将容器中的监听器Bean,设置到广播器中去。

4.普通BeanDefinition生成Bean阶段
此阶段是大部分BeanDefinition生成Bean的阶段。

  • finishBeanFactoryInitialization(beanFactory);:
    此过程,就是上篇文章说的 ,applicationContext上下文触发beanFactory内部的BeanDefinition创建Bean

    我们想象一个场景: 先往一个机器内先放入原料BeanDefinition后,然后再按下开关开始制造.ApplicationContext在此处就好比按下开关.开始Bean的制造,Bean的制作过程是一条流水线,流水线上有不同类型的机器对原料做不同的处理,最终得到Bean

ApplicationContext调用DefaultListableBeanFactory.preInstantiateSingletons()开始触发Bean的创建:

doGetBean:

  1. 首先检查仓库中是否已经创建过此Bean,有取出来
  2. 没有就准备走流水线创建Bean创建.
  3. 创建前先检查物料有没有?有,标记当前Bean在创建中
  4. 检查是否有依赖,有的话,先去加载创建依赖Bean. 又回到了1
  5. 判断作用域,上createBean()流水线准备执行。

doGetBean->createBean:

  1. 加载Bean的Class类
  2. 验证以及准备需要覆盖的方法

doGetBean->createBean->代理对象: 返回代理对象

  1. 创建代理对象:给BeanPostProcessors 一个机会来返回代理对象来代替真正的实例(此处返回的是针对自定义TargetSource的Bean)

doGetBean->createBean->doCreateBean:没有创建自定义代理对象继续执行

  1. 使用合适的实例化策略来创建Bean(工厂方法、构造函数自动注入、简单初始化),并得到Bean包装类BeanWrapper对象。
  2. 调用BeanDefinitionPostProcessor后置处理器,修改 BeanDefinition
  3. 解决单例模式的循环依赖:解决办法是尽早暴露Bean的引用到缓存中,让其他对象可以能引用到他
  4. populateBean设置bean的属性
  5. initializeBean:

doGetBean->createBean->doCreateBean->initializeBean 实例化Bean

  1. invokeAwareMethods:执行_awre类型的方法
  2. applyBeanPostProcessorsBeforeInitialization执行BeanPostProcessor的前置方法
  3. invokeInitMethods: 执行InitializingBean接口的afterPropertiesSet ,invokeCustomInitMethod执行自定义的init-method方法
  4. applyBeanPostProcessorsAfterInitialization:执行BeanPostProcessor的后置方法
  5. 返回Bean. 至此BeanDefinition到Bean的生产过程完成。

5.applicationContext的收尾阶段

  • finishRefresh();
    收尾阶段其实也算是applicationContext的扩展点。Lifecycle接口生命周期接口,

    (1.首先会从Bean容器中获取LifecycleProcessor类型的Bean,如果没有则创建一个默认的DefaultLifecycleProcessor。LifecycleProcessor是干嘛用的?LifecycleProcessor是用来处理Lifecycle接口的bean的。

    (2.使用获得LifecycleProcessor执行实现了Lifecycle接口的Bean的start()方法

    (3.发布上下文初始化完成事件

    (4.Participate in LiveBeansView MBean, if active.不是很清楚干嘛的。

Bean的生命周期

看完了refresh()方法。我们再来总结下Bean的生命周期。

用一张图表示

Bean的完整生命周期分为四个阶段:

  1. 第一阶段:实例化阶段。
    从Bean定义的收集到BeanDefinition的入库顺序执行
    BeanDefinitionRegistryPostProcessor注册处理器,注册一些BeanDefinition
    BeanFactoryPostProcessor,对入库的BeanDefinition进行定义的修改。
    BeanWrapper的产生,BeanWrapper是Bean的早期产品。
    populateBean()执行属性的设置
    总结:此阶段是BeanDefinition->BeanWrapper ,各种属性的设置

  2. 第二阶段:初始化阶段:主要是执行各种初始化方法
    invokeAwareMethods(beanName, bean);执行Aware属性的相关设置。
    BeanPostProcessor.postProcessBeforeInitialization前置方法的执行,
    如果实现了InitializingBean.afterPropertiesSet()则执行此方法
    执行自定义的initMethod方法。
    BeanPostProcessor.postProcessBeforeInitialization后置方法的执行,

  3. 第三阶段:使用阶段
    getBean从容器的缓存中取出Bean

  4. 第四阶段:销毁阶段
    执行DisposableBean.distroy方法
    执行自定义detry-method

总结:

整个spring初始化过程可以看做是

  • 物料(BeanDefinition)的搜集入库(BeanFactory)
  • 生产线(getBean())取出物料创建成品(Bean)
  • 成品(Bean)入库(BeanFactory)

欢迎大家关注我的公众号【源码行动】,最新个人理解及时奉送。

spring源码分析系列5:ApplicationContext的初始化与Bean生命周期的更多相关文章

  1. 【Spring源码分析系列】ApplicationContext 相关接口架构分析

    [原创文章,转载请注明出处][本文地址]http://www.cnblogs.com/zffenger/p/5813470.html 在使用Spring的时候,我们经常需要先得到一个Applicati ...

  2. spring源码分析系列4:ApplicationContext研究

    ApplicationContext接口 首先看一下一个最基本的上下文应该是什么样子 ApplicationContext接口的注释里写的很清楚: 一个基本applicationContext应该提供 ...

  3. spring源码分析系列 (8) FactoryBean工厂类机制

    更多文章点击--spring源码分析系列 1.FactoryBean设计目的以及使用 2.FactoryBean工厂类机制运行机制分析 1.FactoryBean设计目的以及使用 FactoryBea ...

  4. spring源码分析系列

    spring源码分析系列 (1) spring拓展接口BeanFactoryPostProcessor.BeanDefinitionRegistryPostProcessor spring源码分析系列 ...

  5. spring源码分析系列 (5) spring BeanFactoryPostProcessor拓展类PropertyPlaceholderConfigurer、PropertySourcesPlaceholderConfigurer解析

    更多文章点击--spring源码分析系列 主要分析内容: 1.拓展类简述: 拓展类使用demo和自定义替换符号 2.继承图UML解析和源码分析 (源码基于spring 5.1.3.RELEASE分析) ...

  6. spring源码分析系列 (1) spring拓展接口BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor

    更多文章点击--spring源码分析系列 主要分析内容: 一.BeanFactoryPostProcessor.BeanDefinitionRegistryPostProcessor简述与demo示例 ...

  7. spring源码分析系列 (3) spring拓展接口InstantiationAwareBeanPostProcessor

    更多文章点击--spring源码分析系列 主要分析内容: 一.InstantiationAwareBeanPostProcessor简述与demo示例 二.InstantiationAwareBean ...

  8. spring源码分析系列 (2) spring拓展接口BeanPostProcessor

    Spring更多分析--spring源码分析系列 主要分析内容: 一.BeanPostProcessor简述与demo示例 二.BeanPostProcessor源码分析:注册时机和触发点 (源码基于 ...

  9. spring源码分析系列 (15) 设计模式解析

    spring是目前使用最为广泛的Java框架之一.虽然spring最为核心是IOC和AOP,其中代码实现中很多设计模式得以应用,代码看起来简洁流畅,在日常的软件设计中很值得借鉴.以下是对一些设计模式的 ...

随机推荐

  1. 【Offer】[53-2] 【0~n-1中缺失的数字】

    题目描述 思路分析 测试用例 Java代码 代码链接 题目描述 一个长度为n-1的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围0~n-1之内.在范围0~n-1内的n个数字中有且只有一个数字 ...

  2. javascript合并两个数组

    在开发的过程中,我们很多时候会遇到需要将两个数组合并成一个数组的情况出现. var arr1 = [1, 2, 3]; var arr2 = [4, 5, 6]; // 将arr1和arr2合并成为[ ...

  3. Linux常用命令 —— 进程类

    service (CentOs6) 1.service   服务名   start         --------------   启动 2.service   服务名   stop        ...

  4. python接口自动化测试七:获取登录的Cookies

    python接口自动化测试七:获取登录的Cookies,并关联到下一个请求   获取登录的cookies:loginCookies = r.cookies 把获取到的cookies传入请求:cooki ...

  5. QCustomplot使用分享(八) 绘制图表-加载cvs文件

    目录 一.概述 二.效果图 三.源码讲解 1.源码结构 2.头文件 3.移动游标 4.设置坐标轴矩形个数 5.添加图表数据 6.设置折线图类型 6.其他函数 四.测试方式 1.测试工程 2.测试文件 ...

  6. [STL] Implement "vector", ”deque“ and "list"

    vector “可增的”数组 vector是一块连续分配的内存,从数据安排的角度来讲,和数组极其相似. 不同的地方就是: (1) 数组是静态分配空间,一旦分配了空间的大小,就不可再改变了: (2) v ...

  7. vscode Springboot 启动debug报错:Build failed, do you want to continue?

    一,前言 vscode我感觉是一个特别好用的开发工具,我根据文章https://www.cnblogs.com/WangBoBlog/p/9464281.html去搭建一个简单的springboot工 ...

  8. IDEA加密算法(含所需jar包(commons-codec-1.11.jar ,bcprov-jdk15on-160.jar))

    软件设计上机实验IDEA算法: import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.Se ...

  9. jquery的api以及用法总结-属性/css/位置

    属性/css 属性 .attr() attr()设置普通属性,prop()设置特有属性 获取或者设置匹配的元素集合中的第一个元素的属性的值 如果需要获取或者设置每个单独元素的属性值,需要依靠.each ...

  10. Axure实现banner功能

    1.添加一个动态面板,添加上一张.下一张及当前banner对应的序号圆圈,如图所示: 当添加好元素后,实现自动轮播:点击[轮播图面板]页面:选中动态面板:右边添加事件编辑栏——属性——载入时——添加动 ...