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

SpringBoot应用启动过程

Spring 应用抽象

  Springboot 是一个用来快速创建 Spring 应用的微服务框架,启动引导器是org.springframework.boot.SpringApplication 这个类,每个 SpringApplication 实例就表示一个 Spring 应用的启动类;Spring 应用生命周期包括创建、启动、停止。
  Springboot 为 Spring 应用提供了工程创建、开发、运行环境的支持。 Spring 应用服务的抽象包含下面这些元素:

  1. SpringApplication 用来启动一个 Spring 应用的启动引导器,启动的过程就是为 Spring 应用构建运行环境和上下文,并且自动装配应用的组件;整个过程就是 Springboot 的核心技术,也就是自动配置;
  2. ConfigurableEnvironment Spring应用的运行环境,Spring 应用的属性参数等内容都会加载到 ConfigurableEnvironment 中,为 Spring 应用组件的属性配置体统支持;
  3. ApplicationContext Spring 应用的上下文,这是 Spring 应用运行起来后的抽象,是 Spring 应用的运行状态;Spring 应用的形态转化是从 SpringApplication 转化到 ApplicationContextSpringApplication 的主要功能就是创建、初始化、刷新 ApplicationContextApplicationContext 本质上是Spring 的 IOC 容器,管理 Spring 应用组件的生命周期;
  4. SpringFactoriesInstance Spring 应用的工厂实例,就是 Spring 应用系统使用的一些组件实例,这些实例主要用于 Spring 应用以及组件的生命周期管理;这些工厂实例组件的配置一般保存在类路径下的 META-INFO 文件夹下面的 spring.factories 文件内部;该文件内部保存了这些工厂实例的实现类和接口的映射,Spring 应用通过 SpringFactoriesLoader 从该文件下读取 Spring 工厂组件的实现类,并且通过反射进行实例化。
  5. ApplicationListener Spring 应用的监听器,Spring 采取了监听器模式(观察者模式)来对应用的事件进行响应,可以实现 ApplicationListener 并注册到 Spring 应用中来对 Spring 应用生命周期事件进行响应;默认的这些 ApplicationListener 的实现类通过 SpringFactoriesLoader 装载;
  6. ApplicationContextInitializer Spring 使用了钩子模式(hook),定义了钩子接口,通过注册钩子,可以在 Spring 生命周期中插入钩子代码;ApplicationContextInitializer 可以在 ApplicationContext 初始化时加入钩子代码,来进行一些处理;默认的这些 ApplicationContextInitializer 的实现类通过 SpringFactoriesLoader 装载;

SpringApplication

  SpringApplication 是 Spring 应用的启动类,Springboot 通过创建 SpringApplication 实例,然后调用该实例的 run 方法来启动 Spring 应用,成功启动运行的 Spring 应用转换为 ApplicationContext 实例。下面我们看看如何启动 Spring 应用;

创建 SpringApplication 实例

SpringApplication 在创建的时候需要初始化下面的一些属性:

  1. ResourceLoader,设置资源加载器,用于加载 Spring 应用的配置文件,可以为 null,默认实现是 DefaultResourceLoader,也就是 Spring 应用的类路径下面加载资源文件;
  2. primarySources,Spring 应用的启动引导类;也就是 Spring 应用的根配置;
  3. 应用类型推断:webApplicationType 判断 Spring Web 应用的类型,三种类型分别是: Reactive(响应式 Web 服务器)、Servlet(就是 SpringMVC,通过DispatcherServlet 进行请求转发)、none 表示当前应用不是 Web 应用;Spring 通过应用类型推断来确定;判断的依据就是在类路径下面扫描对应的类,如果发现 org.springframework.web.servlet.DispatcherServlet 说明是基于 SpringMVC 的 web 应用,如果发现 org.springframework.web.reactive.DispatcherHandler 说明是响应式 Web 应用;
  4. 装载 Spring 工厂实例,通过 SpringFactoriesLoader 创建用于生命周期管理的监听器类、钩子类、对象工厂等;
  5. initializers,注册 Spring 应用的上下文的初始化器列表,每一个初始化器是一个 ApplicationContextInitializer 实现类,默认的实现类由 SpringFactoriesLoader 装载,可以实现自定义的钩子类,并注册
  6. listeners,注册 Spring 应用事件的监听器列表,这些应用监听器监听 Spring 应用在生命周期变化过程中产生的事件,也就是 ApplicationEvent,对这些事件进行处理;默认的实现类由 SpringFactoriesLoader 装载;
  7. mainApplicationClass,获取应用主程序的类名(main 方法所在的类)
    ####通过 run 方法启动SpringApplication
    SpringApplication 实例的 run 方法用于引导和启动当前的 Spring 应用,并通过一些约定的类来完成应用启动的步骤,一般包括下面几个步骤:
  8. 预备工作;
  9. 准备 ConfigurableEnvironment
  10. 创建 ApplicationContext
  11. 准备 ApplicationContext
  12. 刷新 ApplicationContext
  13. 收尾工作;
1. 预备工作

  预备工作主要是注册 Spring 应用的启动监听器,就是 SpringApplicationRunListeners,每一个监听器是SpringApplicationRunListener 实现类,默认的实现类 EventPublishingRunListenerSpringFactoriesLoader 装载,主要作用是每完成一个阶段,就发布相应的事件;

2. 准备 ConfigurableEnvironment

  为 Spring 应用准备运行环境,这一步创建一个 ConfigurableEnvironment 实例,并将应用参数填充到 ConfigurableEnvironment,比如被激活的 profile 值(profile 就是多环境部署时,用来区分是测试还是生产的) ;然后将 ConfigurableEnvironment 绑定到当前 Spring 应用上;这一步还会去加载 Spring 应用的配置文件(就是 application* 文件),主要过程是通过 EventPublishingRunListener 发布 ApplicationEnvironmentPreparedEvent 事件,通知 ConfigFileApplicationListener 处理;ConfigFileApplicationListener 读取配置文件,加载 propertiesConfigurableEnvironment 实例中;

3. 创建 ApplicationContext

  更具应用类型创建一个合适的应用上下文实例,就是 ApplicationContext 的实现类的实例,org.springframework.context.ApplicationContext 表示 Spring 应用实例运行的上下文环境,包括应用的配置,bean 工厂,应用层级的事件发布器,资源解析器等;根据 Spring 应用的类型,会创建不同的 ApplicationContext 实例;如果应用类型是 servlet ,创建 AnnotationConfigServletWebServerApplicationContext 实例,如果是 reactive,创建 AnnotationConfigReactiveWebServerApplicationContext,如果是 none,也就是非 Web 应用,创建 AnnotationConfigApplicationContext

4. 准备 ApplicationContext

  对创建的 ApplicationContext 进行初始化,会进行下面一些工作:

  1. 通过注册的初始化钩子,就是 ApplicationContextInitializer 实现类进行初始化,比如 ContextIdApplicationContextInitializer 会为当前的 Spring 应用分配一个 ID;
  2. 发布 ApplicationContextInitializedEvent 事件,通知注册的 ApplicationListener 来处理;
  3. 加载 sources 组件;
  4. 将当前 ApplicationContext 实例注入实现了 ApplicationContextAware 接口的 ApplicationListener ;所以如果想获取Spring 应用的 ApplicationContext,可以注册实现了 ApplicationContextAwareApplicationListener
  5. 发布 ApplicationPreparedEvent 事件,通知 ApplicationListener 来处理
    #####5. 刷新 ApplicationContext
      Springboot 的自动化配置就是在这一步实现的,包括 spring.factories 的加载,bean 的实例化等核心工作;
  6. 对 Spring 应用配置的属性(就是application* 文件中的键值对)进行验证;
  7. 刷新内部的 ConfigurableListableBeanFactory
  8. 对 bean 工厂进行初始化,主要是注册一些挂钩实例,Spring IOC 容器使用了挂钩模式,在对组件生命周期管理期间,加入了钩子,就是 Bean 处理器,通过注册挂钩实例来控制 Bean 的生命周期;
  9. 对 bean 工厂进行后置处理;
  10. 执行 Bean 工厂的后置处理器 invokeBeanFactoryPostProcessors,这一步会注册一些 BeanDefinitionRegistryPostProcessor 的实例,并且执行这些处理器,其中有一个实现类叫做 ConfigurationClassPostProcessorConfigurationClassPostProcessor 执行 processConfigBeanDefinitions() 方法来对配置类进行处理;具体的思路是先获取所有的当前所有的 bean definition,并找出配置类对应的 bean definition;接着对容器进行一下转换并实例化一个ConfigurationClassParser 配置类解析器对象 parser,调用 parserparse() 对配置类进行解析;在处理配置 bean 时,ConfigurationClassParser#doProcessConfigurationClass() 会首先迭代地处理所有嵌套的配置类,然后处理所有的 @PropertySource 注解来解析属性源,再处理 @ComponentScan 注解实现自动扫描,再处理 @Import 注解来导入配置类,因为 @SpringBootApplication注解有@EnableAutoConfiguration 注解,而 @EnableAutoConfiguration 有@Import(EnableAutoConfigurationImportSelector.class)注解;@EnableAutoConfiguration 开启了自动装配了,并导入了 EnableAutoConfigurationImportSelector 组件来处理自动装配逻辑
  11. 注册 bean 处理器来拦截 bean 的创建;
  12. 初始化消息源
  13. 初始化 Applicaiton 的事件广播器
  14. 注册一些监听器

最后的工作是由 Spring IOC 容器完成

相关文章:

  • mybatis-plus配置逻辑删除
  • SEO双核驱动:关键词与长尾词优化
  • AI 治理进行时:网信办审核加速,AI 合规刻不容缓
  • 精益数据分析(62/126):从客户访谈评分到市场规模估算——移情阶段的实战进阶
  • 用OBD部署OceanBase社区版的避坑指南
  • 最优化方法Python计算:有约束优化应用——线性不可分问题支持向量机
  • python处理异常,JSON
  • k8s 1.10.26 一次containerd失败引发kubectl不可用问题
  • [Harmony]获取资源文件中.txt文件中的字符串
  • Spring MVC 拦截器 (HandlerInterceptor) 是什么? 它与 Servlet Filter 有什么区别?
  • Python模块化编程
  • 检测按键抖动的时间
  • groovy 如何遍历 postgresql 所有的用户表 ?
  • pytest框架 - 第二集 allure报告
  • 关于xammp数据库打开不了,但是日志没错误的问题解决以及其数据库的备份
  • 广度和深度优先搜索(BFS和DFS)
  • 国产芯片LH001-91为什么可以代替TI的ADS1291?
  • 【沉浸式求职学习day40】【java面试题精选2】
  • 哈夫曼树完全解析:从原理到应用
  • 如何使用易路iBuilder智能体平台快速安全深入实现AI HR【实用帖】
  • 云南德宏州盈江县发生4.5级地震,震源深度10千米
  • 河南省委常委会会议:坚持以案为鉴,深刻汲取教训
  • 沧州制造展现硬核实力:管道装备支撑大国基建,核电锚栓实现国产
  • 颜福庆与顾临的争论:1930年代在中国维持一家医学院要花多少钱
  • 世界期待中美对话合作带来更多确定性和稳定性
  • 韩国总统选战打响:7人角逐李在明领跑,执政党临阵换将陷入分裂