当前位置: 首页 > news >正文

从根儿上学习spring 七 之run方法启动第四段(1)

图1

一步一步我们转眼间来到了第四部分,这是spring最核心的部分包含了bean的整个生命周期过程,不过大家不用担心如果内容过长我会分多个小节来说明以防止一篇文章让大家看晕看累难以吸收理解。让我们直接进入正题。

我们先进入图1的refreshContext方法看看它是如何刷新上下文对象的。该方法主要调用了AbstractApplicationContext#refresh执行刷新逻辑,我们直接看refresh方法。

图2

由图2可以看到refresh方法就是纯粹的调用了很多方法来完成刷新,我们先从第11行prepareBeanFactory(beanFactory);方法开始,因为前两个方法没什么逻辑大家自己点进去看下。

图3

从图3我们看出prepareBeanFactory(beanFactory)方法内部就是调用了beanFactory的一些方法来设置它的内部属性,分别调用了以下一些方法,至于设置的属性细节我们后面用到了再说,不然很多类的逻辑就够用一两篇文章单独来说了。

setBeanClassLoader

   设置当前应用类加载器

setBeanExpressionResolver

   设置表达式解析器,如el表达式解析器

addPropertyEditorRegistrar:

   向beanFactory中添加PropertyEditorRegistry。这里我稍微解释下PropertyEditor,PropertyEditorRegistry,PropertyEditorRegistrar三者的关系。

PropertyEditor:是bean属性编辑器,可以将字符串类型的值转换成其他类型,比如xml里配置的bean属性为字符串但数据类型却可以是Integer,可以通过PropertyEditor来做类型转换

PropertyEditorRegistry:是PropertyEditor的注册表用于维护PropertyEditor,所有的PropertyEditor都要注册在PropertyEditorRegistry里进行维护及使用

PropertyEditorRegistrar: 作用很简单,就是为了把PropertyEditor注册到PropertyEditorRegistry中

addBeanPostProcessor

   添加bean后置处理器---BeanPostProcessor用于bean的生命周期过程中给开发者提供对bean的功能扩展,简单来说就是在bean初始化前后你可以拿到bean对象做些你想做的。该后置处理器有两个方法,分别是postProcessBeforeInitialization---bean初始化前执行及postProcessAfterInitialization---bean初始化后执行,这里的“初始化”指的是执行InitializingBean接口的afterPropertiesSet方法前后。

ignoreDependencyInterface

   该方法是将不需要注入的接口类型进行打标,简单的说就是你不想对这接口类型进行依赖注入,像spring中的ApplicationContextAware就不能依赖注入。

registerResolvableDependency

   该方法是将不会通过自动注入方式注入到spring中的类放到Map, Object> resolvableDependencies属性里,在其他bean需要注入这些类的时候spring会先根据类型到resolvableDependencies属性里查找能找到就返回对应的对象,不然就通过beanFactory.getBean()方法去spring容器创建bean并返回。

setTempClassLoader

   添加临时类加载器,特殊场景时使用

registerSingleton

  向beanFacory中注册实例化好的bean对象,spring会向容器里预先注册spring内部的一些实例对象。

接着看图2postProcessBeanFactory(beanFactory);方法

     该方法允许你对beanFactory进行后置处理也就是对beanFactoty进行一些额外设置和操作。该方法主要由applicationContext的子类实现,我们当前启动的是AnnotationConfigServletWebServerApplicationContext子类它的postProcessBeanFactory(beanFactory)实现是向beanFactory中添加了beanPostProcessor后置处理器WebApplicationContextServletContextAwareProcessor。

    该后置处理器负责在bean初始化之前(这里的初始化也是指的是在执行InitializingBean的afterPropertiesSet方法)判断bean有没有实现ServletContextAware接口,对实现了该接口的bean调用其setServletContext方法设置ServletContext对象。

   其他的applicationContext实现子类对postProcessBeanFactory(beanFactory)方法的实现这里就不做分析了感兴趣的同学自行分析下吧,我们接着往下看。

接着看图2 invokeBeanFactoryPostProcessors(beanFactory)方法

   它会调用PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors())方法执行所有的BeanFactoryPostProcessor接口的postProcessBeanFactory方法。          PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors方法的逻辑准确来说的话就是执行了了两个接口的两个方法,分别是BeanFactoryPostProcessor接口的postProcessBeanFactory方法和BeanDefinitionRegistryPostProcessor接口的postProcessBeanDefinitionRegistry方法,执行顺序是先执行前者再执行后者。

   接口BeanDefinitionRegistryPostProcessor继承了BeanFactoryPostProcessor,从它的命名就可以看出它的作用是对BeanDefinitionRegistry进行后置处理,那么什么是BeanDefinitionRegistry呢?它是维护BeanDefinition的地方,所有的BeanDefinition都会被注册到BeanDefinitionRegistry中,通过它你可以获取所有的BeanDefinition或者向其再添加额外的BeanDefinition或者修改对应的BeanDefinition。

   因为可以通过BeanDefinitionRegistry新增新的beanDefinition,那么也就是通过BeanDefinitionRegistry我们可以向spring中再添加新的BeanFactoryPostProcessor的beanDefinition,从而间接添加新的BeanFactoryPostProcessor接口实现。所以这也是spring安排BeanDefinitionRegistryPostProcessor接口方法在BeanFactoryPostProcessor方法前执行的原因。

  既然BeanDefinitionRegistryPostProcessor是对BeanDefinitionRegistry做后置处理的,那是不是我们写的业务bean对应的BeanDefinition是不是就是在这里被加载到BeanDefinitionRegistry中的呢?答案是肯定的,这里有个特殊的BeanDefinitionRegistryPostProcessor就是ConfigurationClassPostProcessor它会把我们的启动类作为一个配置类来处理读取启动类上的 注解信息并找到我们定义的class位置加载为BeanDefinition,该类的具体逻辑请移步另一篇文章:BeanDefinitionRegistryPostProcessor解析

     在执行BeanFactoryPostProcessor接口时spring提供了执行顺序机制,分别通过PriorityOrdered接口和Ordered接口实现,PriorityOrdered继承了Ordered。spring会优先执行实现了PriorityOrdered接口的BeanFactoryPostProcessor,执行顺序是根据Ordered接口的getOrder方法返回值越小优先级越高。

    然后再获取只实现了Ordered接口的BeanFactoryPostProcessor,一样使用Ordered的getOrder方法返回值来比较大小,返回值越小优先级越大。

以防内容过多导致大家看的头晕,这节我们就先到这。下节继续

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 云计算实训21——mysql-8.0.33-linux-glibc安装及使用
  • 电脑本地如何安装MySQL服务
  • Git详细命令大全
  • 大模型检索增强生成RAG
  • 题解 - 树上游走(二)(上海月赛2024.7甲组T1)
  • Python(模块)
  • 微信小程序实现上传照片功能
  • C#加班统计次数
  • CSS:图片间空白间距问题的解决方案
  • java Path对象和URI对象的转换
  • Python的并行任务(进程池、线程池)
  • 关于vs2022项目占用空间太大的问题
  • MongoDB未授权访问漏洞
  • 【selenium】文件上传、下载、读取
  • TF卡(SD NAND)参考设计和使用提示
  • 【108天】Java——《Head First Java》笔记(第1-4章)
  • 【译】React性能工程(下) -- 深入研究React性能调试
  • 11111111
  • Android开源项目规范总结
  • canvas 高仿 Apple Watch 表盘
  • ES6--对象的扩展
  • js算法-归并排序(merge_sort)
  • Laravel 实践之路: 数据库迁移与数据填充
  • PHP那些事儿
  • React-flux杂记
  • 机器人定位导航技术 激光SLAM与视觉SLAM谁更胜一筹?
  • 力扣(LeetCode)21
  • 前端面试题总结
  • 实战|智能家居行业移动应用性能分析
  • 视频flv转mp4最快的几种方法(就是不用格式工厂)
  • 项目实战-Api的解决方案
  • 用element的upload组件实现多图片上传和压缩
  • 云大使推广中的常见热门问题
  • 继 XDL 之后,阿里妈妈开源大规模分布式图表征学习框架 Euler ...
  • 资深实践篇 | 基于Kubernetes 1.61的Kubernetes Scheduler 调度详解 ...
  • ​linux启动进程的方式
  • ​Spring Boot 分片上传文件
  • ​sqlite3 --- SQLite 数据库 DB-API 2.0 接口模块​
  • ​经​纬​恒​润​二​面​​三​七​互​娱​一​面​​元​象​二​面​
  • ​人工智能之父图灵诞辰纪念日,一起来看最受读者欢迎的AI技术好书
  • "无招胜有招"nbsp;史上最全的互…
  • #gStore-weekly | gStore最新版本1.0之三角形计数函数的使用
  • (arch)linux 转换文件编码格式
  • (层次遍历)104. 二叉树的最大深度
  • (差分)胡桃爱原石
  • (附源码)spring boot基于Java的电影院售票与管理系统毕业设计 011449
  • (附源码)springboot码头作业管理系统 毕业设计 341654
  • (官网安装) 基于CentOS 7安装MangoDB和MangoDB Shell
  • (七)微服务分布式云架构spring cloud - common-service 项目构建过程
  • (亲测)设​置​m​y​e​c​l​i​p​s​e​打​开​默​认​工​作​空​间...
  • (算法)Travel Information Center
  • (心得)获取一个数二进制序列中所有的偶数位和奇数位, 分别输出二进制序列。
  • (学习日记)2024.03.25:UCOSIII第二十二节:系统启动流程详解
  • (一)80c52学习之旅-起始篇
  • (原创)攻击方式学习之(4) - 拒绝服务(DOS/DDOS/DRDOS)