Refresh

ApplicationContext refresh的流程概述

ApplicationContext是spring中的核心容器,refresh是ApplicationContext的一个方法,主要作用是用来初始化ApplicationContext。

refresh一共分为十二个步骤。所有的ApplicationContext有一个共同的父类叫AbstractApplicationContext。这个父类里有refresh方法,这个方法里面有12个比较重要的方法。

image-20220324171011912

1、蓝色:代表做一些准备工作。

2—6、绿色:创建并准备BeanFactory对象。

为什么需要BeanFactory对象呢?

因为ApplicationContext只是一个外部容器,核心功能还需要交给BeanFactory来完成。(Bean的创建、Bean的依赖注入、Bean的初始化)

7—12、黄色:准备我们的ApplicationContext,为ApplicationContext里面一些特有的功能做一些准备。

11、红色:比较重要,是在创建和初始化我们的单例对象。容器当中的单例对象都是在第11步创建并初始化完成的。

1、prepareRefresh

要点
●这一步创建和准备 了Environment对象
●要理解 Environment对象的作用
●跟我学怎么调试代码

prepareRefresh主要就是准备了一个Environment对象,这个环境对象后续的代码里都会用到。

他就是为我们spring后续运行时提供一些键值信息。

systemProperties:java中的一些键值(java中的默认编码、文件分割符等)

systemEnvironment:提供了操作系统的键值对(java_home、path、classPath等)

自定义:从自定义的properties文件当中的读取到的信息。例如application.properties文件。

即Environment的作用就是管理各种键值信息,将来其他地方可以用到这些信息,例如@Value

总结

  • Environment 的作用之一是为后续@Value,值注入时提供键值

@Value怎么获取值并且解析值的过程

我们还需要做进一步解析,解析的时候需要用到Environment(它里面存的是这些键值)

Environment是一个接口,我们使用的时候创建它的实现类即可。

利用Environment获取配置文件中的键值信息

StandardEnvironment只能解析java和系统的键值,我们在配置文件中自定义的键值无法解析到。

解析SpEL表达式

2、obtainFreshBeanFactory

要点

  • 这一步获取(或创建) BeanFactory
  • 理解BeanFactory的作用
  • 理解BeanDefinition的作用
  • BeanDefinition从何而来

image-20220324193938526

1、ApplicationContext和BeanFactory的关系?

第一步ApplicationContext里面有一个成员变量Environment创建好之后。第二步会获得第二个成员变量BeanFactory(ApplicationContext里面会有一个成员变量为BeanFactory)。ApplicationContext和BeanFactory是一个组合的关系。虽然在继承关系上BeanFactory是父接口,ApplicationContext是子接口,也就是说ApplicationContext扩展了一些BeanFactory的一些功能,但是在实际使用中他俩是组合关系。

ApplicationContext里面的一些功能并没有自己去实现,例如创建Bean,依赖注入、初始化,这些功能还是借助成员变量BeanFactory来完成的。

2、BeanFactory的成员变量进行初始化

BeanFactory要现有一些bean的定义,要先知道这个Bean长什么样子(Bean是单例还是多例,bean的初始化方法是什么,他有哪些属性需要依赖注入。这些信息都是使用BeanDefinition这个类去描述的,而benDefinitionMap就是用来存储所有的BeanDefinition)

总结

  • BeanFactory的作用是负责bean的创建、依赖注入和初始化
  • BeanDefinition作为bean的设计蓝图,规定了bean的特征,如单例多例、依赖关系、初始销毁方法等
  • BeanDefinition 的来源有多种多样,可以是通过xml获得、通过配置类获得、通过组件扫描获得,也可以是编程添加

通过配置类获取BeanDefinition

通过Bean工厂的后置处理器去解析定义的配置类。

因为spring的标准功能里是没办法识别加了注解@Bean的方法(spring不能把他识别为一个BeanDefinition),需要后置处理器去解析这些@Bean注解,包括Import,ImportResource注解等,那些注解都需要额外的代码去解析。

Bean工厂的后置处理器,对我们的Bean工厂去做一些功能的增强。可以识别一些注解,将这些注解标记的类也作为BeanDefinition添加到Bean工厂里面去。

扫描指定包下标注了注解的类,将这些类添加到BeanFactory里

总结:BeanFactory就是去创建Bean,但它不是一下子就能把Bean创建出来,需要借助BeanDefinition。ApplicationContext和BeanFactory是组合关系,ApplicationContext在Bean的管理上接住了BeanFactory的功能。

3、prepareBeanFactory

要点

  • 完善BeanFactory
  • 了解谁来解析SpEL
  • 了解谁来执行类型转换
  • 了解特殊bean的注入
  • 两个内置的BeanPostProcessor的作用

顾名思义就是在准备我们的Bean工厂,因为刚开始的Bean工厂里有很多成员变量没有被初始化。所谓的准备Bean工厂就是将这些成员变量初始化好,才能执行后续的工作。

beanExpressionResolver: 解析SpEL表达式,解析#{}的

propertyEditorRegistrars: 注册一些类型转换器(spring在进行值注入的时候,需要把字符串类型转换为其他类型)

resolvableDependencies: 去管理一些特殊的对象用来进行依赖注入。(大部分Bean都是被放在singletonObjects里去完成依赖注入,但是有些特殊的对象能不能注入,比如我想注入BeanFactory本身,我想注入ApplicationContext本身,这些对象不是一个真正的bean,没有在单例池里面,没有在BeanDefinition里面去定义。但是这些Bean也是可以注入的,那么查询这些特殊Bean的时候不是去singletonObjects,而是去resolvableDependencies里面去查询)

beanPostProcessors: 在Bean创建时,对Bean的功能进行一些扩展,对里面的注解进行一些识别。(spring的标准功能里功能是十分有限的,如果要对bean的创建做各种各样的扩展的话,需要借助beanPostProcessors来完成)。一些beanPostProcessors是在bean的创建过程中,对bean的创建、依赖注入各个阶段做一些功能增强。

4、postProcessBeanFactory

它是一个空实现,留给子类去实现。

ApplicationContext有一大类是web环境下的子类,有一大类是非web环境下的子类。web环境下的子类初始化BeanFactory就需要初始化更多的信息,比如要注册一些新的scope,非web环境下只需要singleton和proportype。但是web环境下还需要request、session这些

是一种模板方法的设计模式,refresh方法得主要脉络都被父类给规定死了,但是有一些可以扩展得方法把它留空,将来有子类去实现。

总结.

  • 一般 Web环境的ApplicationContext都要利用它注册新的Scope,完善Web下的BeanFactory
  • 体现的是模板方法设计模式

5、invokeBeanFactoryPostProcessors

要点

  • 理解beanFactory后处理器的作用
  • 掌握常见的beanFactory后处理器

通过后置处理器对bean工厂的另一种扩展方式,第四步把一些功能是留给子类去扩展。

总结

  • beanFactory后处理器,充当beanFactory的扩展点,可以用来补充或修改BeanDefinition
  • ConfigurationClassPostProcessor -解析@Configuration、@Bean、@lmport、 @PropertySource 等=
  • PropertySourcesPlaceHolderConfigurer -替换BeanDefinition中的${}

(正常的BeanFactory是没有解析这些注解的功能的,调用后置处理器ConfigurationClassPostProcessor可以解析他们,同时解析的目的就是为了多加一些BeanDefinition)

BeanFactory有两个扩展点,第一处就是交给子类去扩展,第二处就是交给bean的后置处理器

6、registerBeanPostProcessors

要点

  • 理解bean后处理器的作用
  • 掌握常见的bean后处理器

Bean工厂的后置处理器是对整个Bean工厂的功能进行增强的,但是registerBeanPostProcessors是bean的后置处理器就不一样了,它是对我们接下来bean的创建过程中做各种功能增强。

如果想要ApplicationContext完成各种各样更多的功能,一般就会在第六步加入更多的bean的后置处理器,这些Bean的后置处理器从哪来呢?都是从beanDefinitionMap去搜索,看看这些beanDefinitionMap中有没有人实现了BeanPostProcessors接口。如果实现了接口他就会识别出来,你是一个特殊的bean,是一个bean后置处理器,会把这样的bena创建出来,创建好之后把它添加到beanPostProcessors集合里面。将来在bean创建的时候就会用到这些后置处理器了。

常见的Bean后置处理器

总结

  • bean 后处理器,充当bean的扩展点,可以工作在bean的实例化、依赖注入、初始化阶段
  • AutowiredAnnotationBeanPostProcessor功能有:解析@Autowired, @Value 注解
  • CommonAnnotationBeanPqstProcessor 功能有:解析@Resource, @PostConstruct, @PreDestroy
  • AnnotationAwareAspectJAutoProxyCreator 功能有:为符合切点的目标bean自动创建代理

注意:这一步只是找出来有哪些Bean的后置处理器,将他们加入到beanPostProcessors集合中,但是真正这些后置处理器发挥作用的是在bean的创建过程。(现在只是注册,并没有用到他们)

7、initMessageSource

要点

  • 理解MessageSource的作用
  • MessageSource 从何而来

前面的2-6都是在不断地完善BeanFactory,第七步是给ApplicationContext的成员变量进行初始化和赋值。第七步就是给Message进行初始化赋值的,他就是一个国际化功能。

总结

  • 实现国际化
  • 容器中一个名为messageSource的bean,如果没有,则提供空的MessageSource实现

8、initApplicationEventMulticaster

要点

  • 理解事件广播器的作用
  • 事件广播器从何而来.
  • 如何发布事件

image-20220325202025540

广播器的作用:收发事件。发事件的就是Multicaster,在spring当中设置一些监听器来收事件。当事件发生了Multicaster发送给各个监听器对象。

来源:和MessageSource一样,它也是先去BeanFactory找,看看beanDefinitionMap里面有没有一个Multicaster,如果有,就把他作为applicationEventMulticaster的实现。如果没有,它会提供一个默认的实现。

Multicaster里面有一个集合,这个集合内部维护了所有的监听器,将来Multicatser发事件的时候就会遍历这个集合,将事件发送给对这个事件感兴趣的监听器。

总结

  • 用来发布事件给 监听器
  • 可以从容器中找名为applicationEventMulticaster的bean作为事件广播器,若没有,也会新建默认的事件广播器
  • 可以调用ApplicationContext.publishEvent(事件对象)来发布事件

9、onRefresh

要点

  • 这一步是空实现,留给子类扩展
  • 掌握对应的设计模式

总结

  • SpringBoot 中的子类可以在这里准备WebServer,即内嵌web容器
  • 体现的是模板方法设计模式

10、registerListeners

要点

  • 理解事件监听器作用
  • 监听器从何而来
  • 如何接收事件 .

作用:监听器来接收事件

来源:如果beanDefinitionMap里面的bean实现了ApplicationListerner的接口,在这一步就会把这些bean找出来,将他们加入到Multicaster的集合里。Multicaster发事件的时候就将其发送到监听器集合里。

总结

  • 用来接收事件
  • 部分监听器是事先编程添加的、另一部分监听器来自容器中的bean、还有-部分来自于@EventListener的解析
  • 实现ApplicationListener接口,重写其中onApplicationEvent(E e)方法即可

11、finishBeanFactorylnitialization

要点

  • 了解conversionService
  • 了解内嵌值解析器
  • 单例池- singletonObjects

conversionService:类型转换。

之前的propertyEditorRegistrars就是做类型转换的,为什么还需要conversionService?

因为之前的propertyEditorRegistrars接口功能上不完整,所以又设计了另一套接口。

embeddedValueResolvers:用来解析${}。它相当于又封装了一下,会间接调用Environment。

singletonObjects: 将在fininationMap中的非延迟的单例对象创建出来。(在创建的过程中,beanPostProcessors后置处理器都会派上用场。bean的创建、依赖注入、初始化)

总结

  • conversionService也是一 套转换机制,作为对PropertyEditor的补充
  • 内嵌值解析器用来解析@Value中的${},借用的是Environment的功能
  • 单例池用来缓存所有单例对象,对象的创建都分三个阶段(创建、依赖注入、初始化),每- -阶段都有不同的bean后处理器参与迸来,扩展功能

12、finishRefresh

要点

  • 了解lifecycleProcessor
  • 它从何而来
  • 如何控制lifecycle?
  • 发布ContextRefreshed事件

生命周期处理器(lifecycleProcessor):容器当中有很多的bean,他们都有自己独立的生命周期(服务启动,停止),他也是在容器当中去找看有没有对应周期处理器,如果有就用,没有就有一个默认的。

他里面有个start、stop方法,相当于大哥一样,它的start方法一旦执行,其他bean的start也要执行。它的stop一旦执行,其他bean的stop也要执行。

总结

  • 用来控制容器内需要生命周期管理的bean
  • 如果 容器中有名称为lifecycleProcessor的bean就用它,否则创建默认的生命周期管理器
  • 调用context的start,即可触发所有实现LifeCycle接口bean的start
  • 调用context的stop,即可触发所有实现LifeCycle接口bean的stop

发布事件标识refresh完成。

refresh12个步骤

  1. prepareRefresh-做好准备工作(创建Environment对象,为spring后续的运行提供一些键值信息)
  2. obtainFreshBeanFactory -创建或获取BeanFactory
  3. prepareBeanFactory -准备BeanFactory(为BeanFactory创建各个成员变量,EL表达式解析器、类型转换器、内置的BeanPostProcessor)
  4. postProcessBeanFactory- 子类扩展BeanFactory
  5. invokeBeanFactoryPostProcessors -后处理器扩展BeanFactory(Bean工厂的后置处理器:ConfigurationClassPostProceessors,解析配置类的注解:@Configuration、@Bean等)
  6. registerBeanPostProcessors -准备Bean后处理器(常见的有三个,一个是解析@Autwired注解,一个是解析@Resource、一个是解析@Aspect,创建代理类的)
  7. initMessageSource -为ApplicationContext提供国际化功能
  8. initApplicationEventMulticaster -为ApplicationContext提供事件发布器
  9. onRefresh- 留给子类扩展
  10. registerListeners -为ApplicationContext准备监听器
  11. finishBeanFactorylnitialization -初始化单例Bean,执行Bean后处理器扩展
  12. finishRefresh- 准备生命周期管理器,发布ContextRefreshed事件

2-6:都是在准备BeanFactory

一个是解析@Autwired注解,一个是解析@Resource、一个是解析@Aspect,创建代理类的)
7. initMessageSource -为ApplicationContext提供国际化功能
8. initApplicationEventMulticaster -为ApplicationContext提供事件发布器
9. onRefresh- 留给子类扩展
10. registerListeners -为ApplicationContext准备监听器
11. finishBeanFactorylnitialization -初始化单例Bean,执行Bean后处理器扩展
12. finishRefresh- 准备生命周期管理器,发布ContextRefreshed事件

2-6:都是在准备BeanFactory

从第7开始:回到ApplicationContext,为它的成员进行赋值

【Spring总结】Refresh相关推荐

  1. Spring的refresh()方法调用过程

    Spring的refresh()方法调用过程 refresh()是Spring中比较核心的方法,Spring所有的初始化都在这个方法中完成 具体代码如下 public void refresh() t ...

  2. Spring IOC refresh()方法——告诉子类刷新内部bean工厂

    告诉子类刷新内部bean工厂. /*** Tell the subclass to refresh the internal bean factory.* @return the fresh Bean ...

  3. 【细读Spring Boot源码】重中之重refresh()

    前言 版本:spring-boot-2.7.3 | spring-context-5.3.22 在Spring Boot启动过程中[细读Spring Boot源码]启动步骤 主流程详情7中applic ...

  4. spring 中 ApplicationContext 的 refresh 方法做了什么

    refresh 方法可以说是Spring中核心的一个方法了,通过这个方法可以获取bean的定义.创建添加bean到spring容器中一个其它扩展功能.记录下相关内容. 有个问题:refresh方法为什 ...

  5. 【spring源码系列-05】refresh中prepareRefresh方法的执行流程

    Spring源码系列整体栏目 内容 链接地址 [一]spring源码整体概述 https://blog.csdn.net/zhenghuishengq/article/details/13094088 ...

  6. 没想到,他面试竟然挂在了Spring的这个点上...

    最近很多水友在后台留言问: Spring的循环依赖问题,这也是最近两年新出的面试频度较高的面试题! 下面我们就通过这篇文章让大家了解循环依赖的问题 什么是循环依赖? 循环依赖其实是指两个及以上bean ...

  7. idea spring 中没有标识_Spring 优雅的国际化实现

    国际化 简单来说,国际化就是让应用(app.web)适应不同的语言和地区的需要,比如根据地区选择页面展示语言. i18n=internationalization,首末字符i和n,18为中间的字符数 ...

  8. 不清楚 spring 的这几个知识点,面试直接挂了!

    小A 你好面试官,非常高兴能参加今天的面试 面试官 没事,先做一个自我介绍吧 小A 我叫小A,工作三年了,做过...... 面试官 嗯,好的,看到你的项目这块,在公司主要用的就是spring全家桶相关 ...

  9. spring cloud连载第一篇之bootstrap context

    1. Spring Cloud Context: Application Context Services(应用上下文服务) 1.1 The Bootstrap Application Context ...

  10. 回炉Spring--事务及Spring源码

    声明式事务 配置文件信息: /*** @EnableTransactionManagement 开启基于注解的事务管理功能* 1.配置数据源* 2.配置事务管理器来管理事务* 3.给方法上标注 @Tr ...

最新文章

  1. 黑色星期五阿里云向海淘输出双11技术
  2. WHEN-CREATE-RECORD的三大定律一大推论
  3. Codeforces Gym 100650B Countdown (离线)
  4. 创智播客 大数据_华中人工智能主题产业园——武汉融创智谷
  5. mysql2教程_mySQL 教程 第2章 安装和介绍mySQL
  6. caffe网络结构图绘制
  7. 字符指针与字符串变量的转换
  8. Java工具实现无水印批量下载
  9. 诊断域帐号被锁定的原因
  10. 陈彩君(帮别人名字作诗)
  11. 从零开始搭二维激光SLAM --- Karto的前端实现与解读
  12. Python调用海康威视网络摄像头进行远程人脸识别
  13. 【Unity3D插件】VOXL插件分享《多人沙盒游戏插件》
  14. JavaWeb之HttpSession
  15. dstat 命令详解
  16. 脸上不同部位长痘痘的原因
  17. 发现最新的区块链应用-8月16日
  18. easyX——图形库
  19. android 手机存储大小设置,如何让手机内存变大?内存不足解决方法【详解】
  20. leetcode 17. 电话号码的字母组合

热门文章

  1. 8小时8分:2018年天猫双11交易额破1207亿元 已超2016年全天
  2. pycrypto安装错误
  3. 平衡二叉树(AVL)的左旋转右旋转和双旋转
  4. 修改eps矢量图中的文字
  5. 【用SQLite做数据分析】Python操作SQLite的入门介绍
  6. 腾讯、优酷Android面试
  7. 子网掩码必须是相邻的是什么意思_子网掩码必须是相邻的是什么意思 您输入一个无效的子网掩码...
  8. 常用名称含义(笔记)
  9. Win11如何搭建FTP服务器以实现快速传输文件?
  10. scikit-learn中用gridsearchcv给随机森林(RF)自动调参