不懂SpringApplication生命周期事件?那就等于不会Spring Boot嘛(上)

简介: 不懂SpringApplication生命周期事件?那就等于不会Spring Boot嘛(上)

前言


各位小伙伴大家好,我是A哥。本文属总结性文章,对总览Spring Boot生命周期很是重要,建议点在看、转发“造福”更多小伙伴。


我最近不是在写Spring Cloud深度剖析的相关专栏麽,最近有收到小伙伴发过来一些问题,通过这段时间收集到的反馈,总结了一下有一个问题非常集中:那便是对Spring Boot应用SpringApplication的生命周期、事件的理解。有句话我不是经常挂嘴边说的麽,你对Spring Framework有多了解决定了你对Spring Boot有多了解,你对Spring Boot的了解深度又会制约你去了解Spring Cloud,一环扣一环。因此此问题反馈比较集中是在清理之中的~


为何在Spring Boot中生命周期事件机制如此重要?缘由很简单:Spring Cloud父容器是由该生命周期事件机制来驱动的,而它仅仅是一个典型代表。Spring Cloud构建在Spring Boot之上,它在此基础上构建并添加了一些“Cloud”功能。应用程序事件ApplicationEvent以及监听ApplicationListener是Spring Framework提供的扩展点,Spring Boot对此扩展点利用得非常充分和深入,并且还衍生出了非常多“子”事件类型,甚至自成体系。从ApplicationEvent衍生出来的子事件类型非常多,例如JobExecutionEvent、RSocketServerInitializedEvent、AuditApplicationEvent...


本文并不会对每个子事件分别介绍(也并无必要),而是集中火力主攻Spring Boot最为重要的一套事件机制:SpringApplication生命周期的事件体系



正文


本文将以SpringApplication的启动流程/生命周期各时期发出的Event事件为主线,结合每个生命周期内完成的大事记介绍,真正实现一文让你总览Spring Boot的全貌,这对你深入理解Spring Boot,以及整合进Spring Cloud都将非常重要。

为表诚意,本文一开始便把SpringApplication生命周期事件流程图附上,然后再精细化讲解各个事件的详情。


话外音:赶时间的小伙伴可以拿图走人😁,但不建议白嫖哟


生命周期事件流程图


image.png



版本说明:


由于不同版本、类路径下存在不同包时结果会存在差异,不指明版本的文章都是不够负责任的。因此对导包/版本情况作出如下说明:


  • Spring Boot:2.2.2.RELEASE。有且仅导入spring-boot-starter-web和spring-boot-starter-actuator
  • Spring Cloud:Hoxton.SR1。有且仅导入spring-cloud-context(注意:并非spring-cloud-starter,并不含有spring-cloud-commons哦)


总的来说:本例导包是非常非常“干净”的,这样在流程上才更有说服力嘛~

SpringApplicationEvent


它是和SpringApplication生命周期有关的所有事件的父类,@since 1.0.0。


public abstract class SpringApplicationEvent extends ApplicationEvent {
  private final String[] args;
  public SpringApplicationEvent(SpringApplication application, String[] args) {
    super(application);
    this.args = args;
  }
  public SpringApplication getSpringApplication() {
    return (SpringApplication) getSource();
  }
  public final String[] getArgs() {
    return this.args;
  }
}


它是抽象类,扩展自Spring Framwork的ApplicationEvent,确保了事件和应用实体SpringApplication产生关联(当然还有String[] args)。它有如下实现子类(7个):


image.png


每个事件都代表着SpringApplication不同生命周期所处的位置,下面分别进行讲解。

ApplicationStartingEvent:开始启动中


@since 1.5.0,并非1.0.0就有的哦。不过现在几乎没有人用1.5以下的版本了,所以可当它是标准事件。


完成的大事记

  • SpringApplication实例已实例化:new SpringApplication(primarySources)
  • 它在实例化阶段完成了如下几件“大”事:


  • 推断出应用类型webApplicationType、main方法所在类
  • 给字段initializers赋值:拿到SPI方式配置的ApplicationContextInitializer上下文初始化器

image.png


  • 给字段listeners赋值:拿到SPI方式配置的ApplicationListener应用监听器

image.png


  • 注意:在此阶段(早期阶段)不要过多地使用它的内部状态,因为它可能在生命周期的后期被修改(话外音:使用时需谨慎)


  • 此时,SpringApplicationRunListener已实例化:它通过SPI方式指定org.springframework.boot.SpringApplicationRunListener=org.springframework.boot.context.event.EventPublishingRunListener。
  • 若你有自己的运行时应用监听器,使用相同方式配置上即可,均会生效
  • 由于EventPublishingRunListener已经实例化了,因此在后续的事件发送中,均能够触发对应的监听器的执行
  • 发送ApplicationStartingEvent事件,触发对应的监听器的执行


监听此事件的监听器们


默认情况下,有4个监听器监听ApplicationStartingEvent事件:


image.png



  1. LoggingApplicationListener:@since 2.0.0。对日志系统抽象LoggingSystem执行实例化以及初始化之前的操作,默认使用的是基于Logback的LogbackLoggingSystem
  2. BackgroundPreinitializer:启动一个后台进行对一些类进行预热。如ValidationInitializer、JacksonInitializer...,因为这些组件有第一次惩罚的特点(并且首次初始化均还比较耗时),所以使用后台线程先预热效果更佳
  3. DelegatingApplicationListener:它监听的是ApplicationEvent,而实际上只会ApplicationEnvironmentPreparedEvent到达时生效,所以此处忽略
  4. LiquibaseServiceLocatorApplicationListener:略


总结:此事件节点结束时,SpringApplication完成了一些实例化相关的动作:本实例实例化、本实例属性赋值、日志系统实例化等。

ApplicationEnvironmentPreparedEvent:环境已准备好


@since 1.0.0。该事件节点是最为重要的一个节点之一,因为对于Spring应用来说,环境抽象Enviroment简直太重要了,它是最为基础的元数据,决定着程序的构建和走向,所以构建的时机是比较早的。


完成的大事记


  • 封装命令行参数(main方法的args)到ApplicationArguments里面
  • 创建出一个环境抽象实例ConfigurableEnvironment的实现类,并且填入值:Profiles配置和Properties属性,默认内容如下(注意,这只是初始状态,后面还会改变、添加属性源,实际见最后的截图):

image.png


  • 发送ApplicationEnvironmentPreparedEvent事件,触发对应的监听器的执行
  • 对环境抽象Enviroment的填值,均是由监听此事件的监听器去完成,见下面的监听器详解
  • bindToSpringApplication(environment):把环境属性中spring.main.xxx = xxx绑定到当前的SpringApplication实例属性上,如常用的spring.main.allow-bean-definition-overriding=true会被绑定到当前SpringApplication实例的对应属性上
相关文章
|
17天前
|
存储 运维 安全
Spring运维之boot项目多环境(yaml 多文件 proerties)及分组管理与开发控制
通过以上措施,可以保证Spring Boot项目的配置管理在专业水准上,并且易于维护和管理,符合搜索引擎收录标准。
30 2
|
2月前
|
SQL JSON Java
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
这篇文章介绍了如何在Spring Boot项目中整合MyBatis和PageHelper进行分页操作,并且集成Swagger2来生成API文档,同时定义了统一的数据返回格式和请求模块。
60 1
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
|
2月前
|
Java 开发者 Spring
Spring bean的生命周期详解!
本文详细解析Spring Bean的生命周期及其核心概念,并深入源码分析。Spring Bean是Spring框架的核心,由容器管理其生命周期。从实例化到销毁,共经历十个阶段,包括属性赋值、接口回调、初始化及销毁等。通过剖析`BeanFactory`、`ApplicationContext`等关键接口与类,帮助你深入了解Spring Bean的管理机制。希望本文能助你更好地掌握Spring Bean生命周期。
97 1
|
2月前
|
Java 开发者 Spring
Spring bean的生命周期详解!
本文详细介绍了Spring框架中的核心概念——Spring Bean的生命周期,包括实例化、属性赋值、接口回调、初始化、使用及销毁等10个阶段,并深入剖析了相关源码,如`BeanFactory`、`DefaultListableBeanFactory`和`BeanPostProcessor`等关键类与接口。通过理解这些核心组件,读者可以更好地掌握Spring Bean的管理和控制机制。
93 1
|
2月前
|
缓存 NoSQL Java
Springboot自定义注解+aop实现redis自动清除缓存功能
通过上述步骤,我们不仅实现了一个高度灵活的缓存管理机制,还保证了代码的整洁与可维护性。自定义注解与AOP的结合,让缓存清除逻辑与业务逻辑分离,便于未来的扩展和修改。这种设计模式非常适合需要频繁更新缓存的应用场景,大大提高了开发效率和系统的响应速度。
68 2
|
5月前
|
Java Spring 容器
Spring Boot 启动源码解析结合Spring Bean生命周期分析
Spring Boot 启动源码解析结合Spring Bean生命周期分析
108 11
|
4月前
|
Java Spring 供应链
Spring 框架事件发布与监听机制,如魔法风暴席卷软件世界,开启奇幻编程之旅!
【8月更文挑战第31天】《Spring框架中的事件发布与监听机制》介绍了Spring中如何利用事件发布与监听机制实现组件间的高效协作。这一机制像城市中的广播系统,事件发布者发送消息,监听器接收并响应。通过简单的示例代码,文章详细讲解了如何定义事件类、创建事件发布者与监听器,并确保组件间松散耦合,提升系统的可维护性和扩展性。掌握这一机制,如同拥有一把开启高效软件开发大门的钥匙。
49 0
|
6月前
|
存储 NoSQL Java
大事件后端项目34_登录优化----redis_SpringBoot集成redis
大事件后端项目34_登录优化----redis_SpringBoot集成redis
大事件后端项目34_登录优化----redis_SpringBoot集成redis
|
4月前
|
前端开发 Java 开发者
|
4月前
|
Java Spring
Spring的Bean生命周期中@PostConstruct注解
【8月更文挑战第3天】在Spring框架中,`@PostConstruct`注解标示Bean初始化完成后立即执行的方法。它在依赖注入完成后调用,适用于资源加载、属性设置等初始化操作。若方法中抛出异常,可能影响Bean初始化。与之对应,`@PreDestroy`注解的方法则在Bean销毁前执行,用于资源释放。
150 0