Spring 启动过程

博文目录

文章目录

  • 内容总结
  • new AnnotationConfigApplicationContext
  • ApplicationContext.refresh
    • 底层流程
  • refresh - invokeBeanFactoryPostProcessors
    • BeanFactoryPostProcessor


内容总结

Spring启动流程详解

通常,我们说的 Spring 启动,就是构造 ApplicationContext 对象以及调用 refresh() 方法的过程。

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Application.class);AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(Application.class);
context.refresh();

ApplicationContext 的定位是 Spring 的应用上下文, 负责管理和组织应用程序的各个部分. 从代码层面来说, ApplicationContext 是一个 BeanFactory, 从架构层面来说, ApplicationContext 是比 BeanFactory 更加高级的存在, 它统御 BeanFactory, EnvironmentCapable, MessageSource 等这些组件完成相应的功能, BeanFactory 只是它的一个零件而已. GenericApplicationContext 不继承 DefaultListableBeanFactory 而是将之作为一个属性, 从 BeanFactory 继承来的功能全部委托其持有的 DefaultListableBeanFactory 来执行

大致做了下面的一些事情

  • 构造了一个 DefaultListableBeanFactory 对象
  • 初始化一些基础架构组件
  • 解析配置类, 得到 BeanDefinition, 注册到 BeanFactory 中
    • 解析 @ComponentScan, 完成扫描
    • 解析 @Import
    • 解析 @Bean
  • 初始化 MessageSource 支持国际化
  • 初始化 ApplicationEventMulticaster 支持事件机制, 将用户定义的 ApplicationListener 添加到 ApplicationContext 中
  • 创建 非懒加载的单例 Bean, 并存在 BeanFactory 的单例池中
  • 调用 Liftcycle Bean 的 start 方法
  • 发布 ContextRefreshedEvent 事件

由于 Spring 启动过程中要创建非懒加载的单例 Bean 对象, 那么就需要用到 BeanPostProcessor, 所以 Spring 在启动过程中就需要做两件事

  • 生成默认的 BeanPostProcessor 对象, 并添加到 BeanFactory 中
    • AutowiredAnnotationBeanPostProcessor, 处理@Autowired, @Value
    • CommonAnnotationBeanPostProcessor, 处理@Resource, @PostConstruct, @PreDestroy
    • ApplicationContextAwareProcessor, 处理 ApplicationContextAware 等回调
  • 找到外部用户所定义的 BeanPostProcessor 对象 (类型为 BeanPostProcessor 的 Bean 对象), 并添加到 BeanFactory 中

new AnnotationConfigApplicationContext

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Application.class);public AnnotationConfigApplicationContext(Class<?>... componentClasses) {this();register(componentClasses);refresh();
}public AnnotationConfigApplicationContext() {// todo 会调用父类的无参构造方法, super(); 创建 BeanFactory (DefaultListableBeanFactory)StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");// new Reader, 用来支持 ApplicationContext 的 register 等功能this.reader = new AnnotatedBeanDefinitionReader(this);createAnnotatedBeanDefReader.end();// new Scanner, 用来支持 ApplicationContext 的 scan 功能this.scanner = new ClassPathBeanDefinitionScanner(this);
}

AnnotationConfigApplicationContext

  • 调用父类 GenericApplicationContext 的构造方法, 生成 DefaultListableBeanFactory 并赋值给 this.beanFactory
  • 构造 AnnotatedBeanDefinitionReader, 添加一些基础的 PostProcessor, 为 ApplicationContext 提供 register BeanDefinition 的功能
    • 设置 BeanFactory 的 dependencyComparator 为 AnnotationAwareOrderComparator, 它是一个Comparator, 是用来进行排序的, 会获取某个对象上的 Order 注解或者通过实现 Ordered 接口所定义的值进行排序
    • 设置 BeanFactory 的 autowireCandidateResolver 为 ContextAnnotationAutowireCandidateResolver, 多级继承, 每级提供不同的功能, 如 @Lazy 字段生成代理, @Qualifier 解析, 判断某个 Bean 是否可用于依赖注入 (isAutowireCandidate)
    • 添加 BeanDefinition ConfigurationClassPostProcessor, 是一个 BeanFactoryPostProcessor, 用于解析配置类, 涉及到扫描
    • 添加 BeanDefinition AutowiredAnnotationBeanPostProcessor, 用于处理与 @Autowired, @Value 注解相关的内容, 包括推断构造方法, 依赖注入点查找, 执行注入 等
    • 添加 BeanDefinition CommonAnnotationBeanPostProcessor, 用于处理与 @Resource, @PostConstruct, @PreDestroy 注解相关的内容, 包括依赖注入点查找, 执行依赖注入 等
    • 添加 BeanDefinition EventListenerMethodProcessor, 具体见下方 refresh 中的 registerListeners 阶段, 一个 Bean 中如果有一个方法加了 @EventListener 注解, 将由 EventListenerMethodProcessor 解析处理, 它是一个 BeanFactoryPostProcessor, EventListenerMethodProcessor 实现了 SmartInitializingBean 接口, 当所有非懒加载单例 Bean 创建完后, 会调用实现该接口的 Bean 的 afterSingletonsInstantiated 方法, 方法内, 拿到所有 BeanNames, 遍历调用 processBean 方法, 找到其加了 EventListener 注解的方法, 现在还不能去调用, 默认使用 DefaultEventListenerFactory 将该方法构造成 ApplicationListenerMethodAdapter (实现了 ApplicationListener), 添加到 ApplicationContext 的 listener 中
    • 添加 BeanDefinition DefaultEventListenerFactory, 同上
  • 构造 ClassPathBeanDefinitionScanner, 可以用来扫描得到并注册 BeanDefinition
    • 设置 this.includeFilters = AnnotationTypeFilter(Component.class)
    • 设置 environment
    • 设置 resourceLoader
  • 利用 reader 注册 Application.class 为 BeanDefinition, 类型为 AnnotatedGenericBeanDefinition

ApplicationContext.refresh

/*** Load or refresh the persistent representation of the configuration, which* might be from Java-based configuration, an XML file, a properties file, a* relational database schema, or some other format.* <p>As this is a startup method, it should destroy already created singletons* if it fails, to avoid dangling resources. In other words, after invocation* of this method, either all or no singletons at all should be instantiated.* @throws BeansException if the bean factory could not be initialized* @throws IllegalStateException if already initialized and multiple refresh* attempts are not supported*/
void refresh() throws BeansException, IllegalStateException;

这是 ConfigurableApplicationContext 接口上 refresh 方法的注释, 意思是: 加载或刷新持久化的配置, 可能是XML文件, 属性文件, 关系数据库中存储的. 由于这是一个启动方法, 如果失败, 它应该销毁已经创建的单例, 以避免占用资源. 换句话说, 在调用该方法之后, 应该实例化所有的单例, 或者根本不实例化单例

Spring 提供了多种 ApplicationContext, 可刷新的和不可刷新的, 不能刷新是指不能重复刷新, 只能调用一次 refresh 方法, 第二次时会报错

  • AbstractRefreshableApplicationContext, AbstractRefreshableWebApplicationContext, AnnotationConfigWebApplicationContext
  • GenericApplicationContext, AnnotationConfigApplicationContext

底层流程

ConfigurableApplicationContext#refresh, 以 AnnotationConfigApplicationContext 为例

  • prepareRefresh
    • 给子类提供了额外添加 kv 到 Environment 的方式, 检查必要 kv 是否存在, 额外赋了几个值
  • obtainFreshBeanFactory
    • 给子类提供刷新 BeanFactory 的抽象, 由子类决定是否支持, 支持的话, 销毁旧 Bean, 关闭旧 BeanFactory, 重新创建新的 BeanFactory, 返回 BeanFactory
    • SpringMVC / SpringBoot 等可能需要刷新容器, 比如热部署等
  • prepareBeanFactory
    • 设置 BeanFactory 的类加载器
    • 设置 BeanFactory 的表达式解析器, StandardBeanExpressionResolver, 用来解析 SpringEL
    • 添加类型转化注册器, ResourceEditorRegistrar, 自带注册一些默认的 String 转其他对象的转换器
    • 添加 BeanPostProcessor ApplicationContextAwareProcessor, 用来执行 ApplicationContext 相关 Aware 的 Setter 回调方法
    • 添加 ignoredDependencyInterfaces, 忽略指定接口对应 Setter 方法在依赖注入阶段的执行, 因为在依赖注入阶段后还有 Aware 执行阶段也要执行, 否则会执行两次, 没有必要. 比如通过 @Bean(byType/byName) 配置的 Bean, 在依赖注入时会判断实现的接口是否在这个列表中, 在的话就不执行对应 Setter 方法. 而如果给对应 Setter 方法加上 @Autowired 注解则没有此效果, 依赖注入阶段会因 @Autowired 的原因注入一次, 后面的 Aware 阶段又会执行一次
      • AbstractAutowireCapableBeanFactory - autowireByType/autowireByName- unsatisfiedNonSimpleProperties - isExcludedFromDependencyCheck - isSetterDefinedInInterface 里面就会用到 ignoredDependencyInterfaces 这个列表
      • EnvironmentAware, EmbeddedValueResolverAware, ResourceLoaderAware, ApplicationEventPublisherAware, MessageSourceAware, ApplicationContextAware, ApplicationStartupAware
      • BeanNameAware, BeanFactoryAware, BeanClassLoaderAware, 这三个在构造 DefaultListableBeanFactory 的时候添加
    • 添加 resolvableDependencis, 指定某些类型对应的 Bean, 比如要通过 @Autowired 注入一个 ApplicationContext, 我们没有配置这样的 Bean, 但仍然能注入成功, 就是因为这个原因. 在 ByType 依赖注入时, 会先从这个属性中根据类型找 Bean
      • BeanFactory: BeanFactory
      • ResourceLoader: ApplicationContext
      • ApplicationEventPublisher: ApplicationContext
      • ApplicationContext: ApplicationContext
    • 添加 BeanPostProcessor ApplicationListenerDetector, 用于在 Bean 初始化后检测 Bean 是否为 ApplicationListener, 是的话添加到 ApplicationContext 的 listener 中
    • 添加 BeanPostProcessor LoadTimeWeaverAwareProcessor, 负责处理实现 LoadTimeWeaverAware 接口的 Bean 的 Setter 方法的调用
    • 添加一些 Bean 到单例池
      • environment: ApplicationContext 的 Environment
      • systemProperties: 操作系统环境变量, ApplicationContext 的 Environment 中的 SystemProperties
      • systemEnvironment: JVM 环境变量, ApplicationContext 的 Environment 中的 SystemEnvironment
      • applicationStartup: 监控对象
  • postProcessBeanFactory, 模板方法, 子类实现, 补充一些上面通用流程之外的内容, 大多都是和 Web 有关
    • 比如 GenericWebApplicationContext 会补充一些 Web Servlet 相关的内容, 如 BeanPostProcessor, ignoreDependencyInterface, ResolvableDependency, 单例 Bean, request/session/application 作用域等
  • invokeBeanFactoryPostProcessors, 执行BeanFactoryPostProcessor, 会执行 scanner.scan, 将扫描到的 BeanDefinition 注册到 BeanFactory 中
    • 下面单独说
  • registerBeanPostProcessors, 将扫描到的 BeanPostProcessor (比如自己定义的 BeanPostProcessor) 实例化并排序, 并添加到 BeanFactory 的 beanPostProcessors 中, 最后再重新添加一个 ApplicationListenerDetector 对象 (之前其实就添加了过,这里是为了把 ApplicationListenerDetector 移动到最后)
  • initMessageSource, 初始化国际化组件, ApplicationContext 的国际化实现是通过 MessageSource 提供的, MessageSource 通常是我们自己定义的
  • initApplicationEventMulticaster, 初始化事件广播器, 事件广播器是 ApplicationContext 的事件广播实现, 通常是我们自己定义的
    • ApplicationContext.publishEvent(“111”) 底层就是通过 ApplicationEventMulticaster.multicastEvent 实现的
    • 发布的事件分 ApplicationEvent 和 PayloadApplicationEvent, 自定义的消息在监听到后需要转换为 PayloadApplicationEvent 才能看到具体内容
  • onRefresh, 模板方法, 子类实现, 给子类提供的一个 Refresh 回调
  • registerListeners, 将扫描到的 ApplicationListener (比如自己定义的事件监听器) 添加到 ApplicationEventMulticaster 中, 便于事件发布时能通知到对应监听器. 因为这时 FactoryBean 还没有调用 getObject 方法生成 Bean 对象, 所以这里要再根据类型找一下 ApplicationListener, 记录一下对应的 beanName
    • 注册监听器有多种方式, 如 Bean 实现 ApplicationListener 接口, 或 方法添加 ApplicationEvent 参数, 添加 @EventListener 注解
    • 一个 Bean 如果实现了 ApplicationListener 接口, 在初始化后阶段, 将由 ApplicationListenerDetector 这个 BeanPostProcessor 识别并加入到 ApplicationContext 的 listener 中. 即使这个 Bean 是懒加载的也没有关系(虽然实例化全部非懒加载 Bean 的流程在这一步后面), 因为在往事件多播器中注册的时候, 会对监听器执行 getBean, 懒加载的也会被创建出来.
      • ApplicationListenerDetector, 在前面 refresh 的 prepareBeanFactory 阶段添加到 beanPostProcessors 中
    • 一个 Bean 中如果有一个方法加了 @EventListener 注解, 将由 EventListenerMethodProcessor 解析处理, 它是一个 BeanFactoryPostProcessor, EventListenerMethodProcessor 实现了 SmartInitializingBean 接口, 当所有非懒加载单例 Bean 创建完后, 会调用实现该接口的 Bean 的 afterSingletonsInstantiated 方法, 方法内, 拿到所有 BeanNames, 遍历调用 processBean 方法, 找到其加了 EventListener 注解的方法, 现在还不能去调用. 默认使用 DefaultEventListenerFactory 将该方法构造成 ApplicationListenerMethodAdapter (实现了 ApplicationListener), 添加到 ApplicationContext 的 listener 中
      • EventListenerMethodProcessor, 在 new ApplicationConfigApplicationContext 初始化 Reader 的时候, 就会添加成为 BeanDefinition
      • DefaultEventListenerFactory, 在 new ApplicationConfigApplicationContext 初始化 Reader 的时候, 就会添加成为 BeanDefinition
  • finishBeanFactoryInitialization, 实例化所有非懒加载的单例 Bean
  • finishRefresh, 完成刷新
    • 初始化一个 LifecycleProcessor, 不存在就用 DefaultLifecycleProcessor
      • Spring 容器也有生命周期的概念, 比如一个 Bean 实现了 SmartLifecycle, 就可以覆盖 start / stop 等方法来监听容器的状态
      • finishRefresh 中调用 start, ApplicationContext.close() 时调用 stop, isRunning 返回 false 才会调用 start, 返回 true 才会调用 stop
    • 调用 lifecycleProcessor 的 onRefresh 方法, 如果是 DefaultLifecycleProcessor, 那么会获取所有类型为 Lifecycle 的 Bean 对象, 然后调用它的 start 方法, 这就是 ApplicationContext 的生命周期扩展机制
    • 发布刷新完成事件 ContextRefreshedEvent

refresh - invokeBeanFactoryPostProcessors

invokeBeanFactoryPostProcessors 阶段, 会调用所有 BeanFactoryPostProcessor 的方法, 这个阶段在创建非懒加载单例 Bean 的 finishBeanFactoryInitialization 阶段之前, 所以此阶段对 BeanDefinition 的修改是有效的

BeanFactoryPostProcessor

BeanPostProcessor 用于操作 Bean, 即方法入参都是一个 Bean

BeanFactoryPostProcessor 与之类似, 只不过是用于操作 BeanFactory, 只提供了一个方法 postProcessBeanFactory, 方法入参是一个 ConfigurableListableBeanFactory, 这个工厂不支持注册 BeanDefinition, 但是能获取 BeanDefinition, 然后修改其内容

BeanDefinitionRegistryPostProcessor 是 BeanFactoryPostProcessor 的子接口, 额外提供了一个方法 postProcessBeanDefinitionRegistry, 入参是一个 BeanDefinitionRegistry, 这个支持注册 BeanDefinition

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/624033.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Debezium发布历史68

原文地址&#xff1a; https://debezium.io/blog/2019/09/05/website-documentation-overhaul/ 欢迎关注留言&#xff0c;我是收集整理小能手&#xff0c;工具翻译&#xff0c;仅供参考&#xff0c;笔芯笔芯. 网站和文档大修 2019 年 9 月 5 日 作者&#xff1a; 克里斯克兰福…

网络安全|GitHub 已成为恶意软件传播的严重污染源

Recorded Future 凸显了全球合法平台威胁的上升。 根据 Recorded Future最近 的一份报告&#xff0c;开发者平台GitHub最近已成为黑客用来托管和传播恶意软件的流行工具。 该平台为攻击者提供了将其行为伪装成合法网络流量的能力&#xff0c;这使得跟踪和确定攻击者的身份变得…

ubuntu20.04 deepstream 6.3安装

1.基础环境gstreamer sudo apt install \ libssl-dev \ libgstreamer1.0-0 \ gstreamer1.0-tools \ gstreamer1.0-plugins-good \ gstreamer1.0-plugins-bad \ gstreamer1.0-plugins-ugly \ gstreamer1.0-libav \ libgstreamer-plugins-base1.0-dev \ libgstrtspserver-1.0-0 …

C练习——模拟投掷6000次骰子

题目&#xff1a; 模拟骰子投6000次&#xff0c;并计算每一面出现的概率 解析&#xff1a; 6000次&#xff0c;首先想到用数组记录六个面各出现次数 其次&#xff0c;使用随机数&#xff08;1~6的数&#xff09;模拟骰子 然后统计1~6每个数出现的几次&#xff0c;最后除以6…

CentOS命令大全:从入门到精通

博客前言 欢迎来到《CentOS命令大全&#xff1a;从入门到精通》的博客&#xff01;在本文中&#xff0c;我们将深入探讨CentOS操作系统中的各种命令&#xff0c;帮助您从初学者成长为精通者。 CentOS作为一款稳定、高效的Linux发行版&#xff0c;广泛应用于服务器和云计算环境…

倒F天线设计经验分享

一、IFA天线理论分析 为了改善&#xff29;&#xff2c;&#xff21;天线难以使用的缺点&#xff0c;在&#xff29;&#xff2c;&#xff21;天线的基础上再增加一个倒L结构&#xff0c;形成IFA天线&#xff0c;此种天线体积小、易于匹配并具有双极化的特点&#xff0c;而在蓝…

基于springboot的二手车交易系统的设计与实现

&#x1f345;点赞收藏关注 → 私信领取本源代码、数据库&#x1f345; 本人在Java毕业设计领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目希望你能有所收获&#xff0c;少走一些弯路。&#x1f345;关注我不迷路&#x1f345;一 、设计说明 1.1 课题背景 二…

15.kubernetes部署Longhorn

Longhorn 简介 Longhorn是一个轻量级且功能强大的云原生Kubernetes分布式存储平台,可以在任意基础设施上运行。Longhorn与Rancher结合使用,将帮助您在Kubernetes环境中轻松、快速和可靠地部署高可用性持久化块存储。 Longhorn解决了Kubernetes存储的复杂性问题,它是一个可…

Python八股文总结

一. Python基本数据结构有哪四种&#xff1f;区别是什么&#xff1f; 列表&#xff08;List&#xff09;元组&#xff08;Tuple&#xff09;字典&#xff08;Dictionary&#xff09;集合&#xff08;Set&#xff09; 区别主要在于它们的可变性&#xff08;是否可以修改&#x…

交换机批量巡检、配置软件

使用Python3.8实现&#xff0c;支持huawei\h3c\cisco三种交换机批量巡检或者批量配置。 要求&#xff1a;同一种类型的交换机有相同的登录账号和密码&#xff0c;开启ssh服务。 可以查看mac地址是否漂移或者欺骗、ip地址与MAC对应关系&#xff0c;可以查看是否有环路&#xf…

AI 图像自动补全 Uncrop 工具介绍

ClipDrop Uncrop是一款基于AI的图像自动补全工具&#xff0c;由StabilityAI旗下的Clipdrop开发。通过利用StableDiffusionXL开发的算法和深度学习技术&#xff0c;Uncrop可以对用户上传的图片进行自动扩展和补全&#xff0c;改变图片尺寸&#xff0c;使得图像内容得到更完整的呈…

组件v-model

最近看到vue版本更新到3.4.x了&#xff0c;其中有个defineModel API&#xff0c;defineModel在3.3的时候是作为实验特性发布的&#xff0c;在3.4中逐渐稳定。这个API就是Vue3简化组件v-model的写法的&#xff0c;所以这篇就一块儿来总结一下vue中的组件v-model 官网的示例 先说…

互联网上门洗衣洗鞋工厂系统搭建;

随着移动互联网的普及&#xff0c;人们越来越依赖手机应用程序来解决生活中的各种问题。通过手机预约服务、购买商品、获取信息已经成为一种生活习惯。因此&#xff0c;开发一款上门洗鞋小程序&#xff0c;可以满足消费者对于方便、快捷、专业的洗鞋服务的需求&#xff0c;同时…

Vue-组件缓存-keep-alive

1. 介绍 在Vue.js中&#xff0c;组件的复用和缓存是一个重要的优化手段。当我们频繁切换组件时&#xff0c;频繁的销毁和重建会带来一定的性能开销。为了解决这个问题&#xff0c;Vue提供了一个名为keep-alive的抽象组件。下面我们将深入探讨keep-alive的工作原理、使用场景和…

Python学习之路-异常

Python学习之路-异常 简介 程序在运行时&#xff0c;如果 Python 解释器 遇到到一个错误&#xff0c;会停止程序的执行&#xff0c;并且提示一些错误信息&#xff0c;这就是异常。程序停止执行并且提示错误信息这个动作&#xff0c;我们通常称之为&#xff1a;抛出(raise)异常…

MYSQL第三次作业--单表查询

第三次作业 一、创建worker表 mysql> create table worker(-> 部门号 int(11) not null,-> 职工号 int(11) not null,-> 工作时间 date not null,-> 工资 float(8,2) not null,-> 政治面貌 varchar(10) not null default群众,-> 姓名 varchar(20) not n…

华为OD机试真题-开源项目热榜--Java-OD统一考试(C卷)

题目描述: 某个开源社区希望将最近热度比较高的开源项目出一个榜单,推荐给社区里面的开发者。对于每个开源项目,开发者可以进行关注(watch)、收藏(star)、fork、提issue、提交合并请求(MR)等。 数据库里面统计了每个开源项目关注、收藏、fork、issue、MR的数量,开源项目的热…

【无主之地3】最详细的补丁教程(酸奶公园)

【无主之地3】最详细的补丁教程&#xff08;酸奶公园&#xff09; steam已有游戏 1.迅雷种子下载文件&#xff0c;只用下载AddtionalContent这一个&#xff0c;放在文件夹OakGame下 2.将文件夹Engine&#xff1e;Binaries&#xff1e;ThirdParty&#xff1e;steamworks&a…

人脸识别(Java实现的)

虹软人脸识别&#xff1a; 虹软人脸识别的地址&#xff1a;虹软视觉开放平台—以免费人脸识别技术为核心的人脸识别算法开放平台 依赖包&#xff1a; 依赖包是从虹软开发平台下载的 在项目中引入这个依赖包 pom.xml <!-- 人脸识别 --><dependency><gr…

DeepFloyd IF:由文本生成图像的强大模型,能够绘制文字的 AI 图像工具

文章目录 一、DeepFloyd IF 简介二、DeepFloyd IF模型架构三、DeepFloyd IF模型生成流程四、DeepFloyd IF 模型定义 一、DeepFloyd IF 简介 DeepFloyd IF&#xff1a;能够绘制文字的 AI 图像工具 之前的 Stable Diffusion 和 Midjourney 都无法生成带有文字的图片&#xff0c;…