找回密码
 立即注册
首页 业界区 安全 阿里面试:SpringBoot启动时, 如何执行扩展代码? ...

阿里面试:SpringBoot启动时, 如何执行扩展代码?

谯梨夏 8 小时前
本文 的 原文 地址

原始的内容,请参考 本文 的 原文 地址

本文 的 原文 地址
尼恩说在前面

在40岁老架构师 尼恩的读者交流群(50+)中,最近有小伙伴拿到了一线互联网企业如得物、阿里、滴滴、极兔、有赞、希音、百度、网易、美团、蚂蚁、得物的面试资格,遇到很多很重要的相关面试题:
阿里一面:如何在SpringBoot启动时执行特定代码?
SpringBoot 的扩展点有哪些?
SpringBoot 的扩展点、和SpringBoot 启动中的发布订阅的事件机制,有什么关系?
SpringBoot 的扩展点 有哪些类型?
你们项目中, 对 SpringBoot 进行过 哪些 扩展?
最近有小伙伴在面 阿里,问到了相关的面试题,可以说是逢面必问。
小伙伴没有系统的去梳理和总结,所以支支吾吾的说了几句,面试官不满意,面试挂了。
所以,尼恩给大家做一下系统化、体系化的梳理,使得大家内力猛增,可以充分展示一下大家雄厚的 “技术肌肉”,让面试官爱到 “不能自已、口水直流”,然后实现”offer直提”。
最终,机会爆表,实现”offer自由” 。
当然,这道面试题,以及参考答案,也会收入咱们的 《尼恩Java面试宝典PDF》V175版本,供后面的小伙伴参考,提升大家的 3高 架构、设计、开发水平。
《尼恩 架构笔记》《尼恩高并发三部曲》《尼恩Java面试宝典》的PDF,请到文末公号【技术自由圈】获取
本文作者:

  • 第一作者 老架构师 肖恩(肖恩 是尼恩团队 高级架构师,负责写此文的第一稿,初稿 )
  • 第二作者 老架构师 尼恩 (45岁老架构师, 负责 提升此文的 技术高度,让大家有一种 俯视 技术、俯瞰技术、 技术自由 的感觉
现状:能 暴击面官的 顶级高手,不到10%

经过 尼恩团队 对 社群1000多 5年以上经验的开发小伙伴的了解和分析,真正能在 SpringBoot 的架构和源码这块掌握得好的人很少。
尽管大家都知道 SpringBoot 的架构和源码 非常重要,很多的人,一直在学这块,和研究这块,但是 太多的人 在死记硬背。
甚至说 90%的人, 在死记硬背,过两个月就忘记了。
面试的时候,也回答不到 Spring 的源码 底层思维/ 底层原理
真正 理解了 Spring 的源码 底层思维/ 底层原理,做到 能 暴击面官的 ,比例 不到10%。
1.png

本文,尼恩从设计模式入手 , 带大家 穿透 Spring 的源码 , 帮大家 暴击面官。
问题答案

在 Spring Boot 应用中,主要通过 SpringBoot 的扩展点 ,实现 在启动阶段执行特定代码。
SpringBoot 主要的扩展点

方式 执行时机 特点
CommandLineRunner应用完全启动后,接收原始命令行参数简单直接,适合处理命令行参数
ApplicationRunner应用完全启动后,接收结构化参数参数处理更灵活
@EventListener监听特定启动事件可以精确控制执行阶段
ApplicationListener实现接口监听应用事件更底层的事件控制
SmartInitializingSingleton所有单例Bean初始化完成后适合需要在所有Bean就绪后执行的逻辑
@PostConstructBean初始化完成后仅限于单个Bean的生命周期
SpringApplicationRunListener贯穿整个启动过程需要实现多个方法,适合框架级扩展
BeanPostProcessor每个Bean初始化前后粒度最细,可以干预每个Bean的创建过程
2、扩展点的执行时机

2.png

spring boot 中这么多扩展点,源码中的触发点在那,在那个时机执行的?
如何选择合适的扩展点执行特定代码呢?
Spring Boot扩展点分类 与 选择

如果对于spring boot扩展点做大致分类,可以分为两类

  • 事件类 扩展点: 基于 观察者模式 的事件类扩展点 , 被动接收模式
  • 非事件类扩展点: 基于 模版模式 的非事件类扩展点(比如后置处理器 BeanFactoryPostProcessor,CommandLineRunner等) ,主动调用模式
1、扩展点分类统计

根据Spring Boot官方文档及源码分析,我将核心扩展点分类统计如下:
类型 扩展点名称/机制 数量 占比
事件类ApplicationEvent 子类12+75%
〰️@EventListener 监听机制-
非事件类ApplicationRunner125%
〰️CommandLineRunner1
〰️SpringApplicationRunListener1
〰️ApplicationContextInitializer1
〰️BeanFactoryPostProcessor1
总计16+100%
尼恩社群,一个塔尖、硬核 技术 研究圈 , 我们对 Spring Boot 扩展点分类统计 的研究结果是: 事件类扩展点 占绝对主导(≈75%),非事件类较少(≈25%)
3.png

(1) 事件类扩展点 占绝对主导(≈75%):
12个核心事件 + @EventListener机制
(2) 非事件类扩展点 较少(≈25%):
6个主要接口式扩展点 , 模版模式
(3) 未计入@PostConstruct等通用扩展机制
2、扩展点选择决策指南

(1)优先选择事件类扩展点的场景(推荐80%场景)

4.png

比如: 资源预热 → ApplicationReadyEvent
  1. @EventListener(ApplicationReadyEvent.class) public void warmupCache() { // 异步预热缓存 CompletableFuture.runAsync(() -> cacheService.preload()); }
复制代码
通过尼恩团队的研究, Spring Boot 12个核心启动事件详解
根据 Spring Boot 官方文档(3.x 版本)和源码分析,以下是构成事件类扩展点主体的 12 个核心事件及其触发时机和作用:
序号 事件类型 触发时机 核心作用 是否可修改容器
1ApplicationStartingEventSpringApplication.run() 执行后立即触发最早介入点,注册自定义监听器
2BootstrapContextInitializedEvent引导上下文(BootstrapContext)初始化后配置加密/密钥管理的最佳时机
3ApplicationEnvironmentPreparedEvent环境对象(Environment)准备完成,但尚未加载配置文件动态修改配置的最后机会(如:添加 PropertySource)
4ApplicationContextInitializedEventApplicationContext 初始化完成,但尚未加载 Bean定义执行早期容器定制(如设置活动 profiles)
5ApplicationPreparedEventBean 定义加载完成,但实例化之前最后修改 Bean 定义的机会(添加自定义 BeanPostProcessor)
6ContextRefreshedEvent上下文完全刷新后触发(Spring Framework 原生事件)执行需要完整上下文的操作⚠️ 风险操作
7WebServerInitializedEvent内嵌 Web 服务器(Tomcat/Jetty)启动完成获取服务器端口等运行时信息
8ApplicationStartedEvent上下文已刷新,但未触发 ApplicationRunner资源预热准备(如缓存加载)⚠️ 只读访问
9AvailabilityChangeEvent (Liveness)应用进入活动状态(LivenessState.CORRECT)Kubernetes 存活探针准备
10ApplicationReadyEvent所有 ApplicationRunner 执行完毕业务初始化安全点(可安全访问服务)⚠️ 只读访问
11AvailabilityChangeEvent (Readiness)应用就绪可接收流量(ReadinessState.ACCEPTING_TRAFFIC)Kubernetes 就绪探针触发
12ApplicationFailedEvent启动过程任何阶段失败时触发失败处理(如发送告警、记录诊断日志)
注:Spring Boot 2.x 中 ApplicationReadyEvent 和 ApplicationStartedEvent 合并为单一事件
(2) 非事件类扩展点的选择 场景(20%特殊情况)

场景 推荐扩展点 优势
简单命令行参数处理CommandLineRunner参数直接访问
应用级初始化逻辑ApplicationRunner封装好的 ApplicationArguments
早期容器操作SpringApplicationRunListener在事件系统初始化前介入
容器刷新前修改Bean定义BeanDefinitionRegistryPostProcessor深度控制Bean加载
为啥 SpringApplicationRunListener 的属于非事件类扩展点?

SpringApplicationRunListener 是 Spring Boot 启动架构中的核心非事件类扩展点,尽管其名称包含 "Listener",但在扩展机制分类中属于非事件类扩展点
1、分类依据

1). 实现机制对比

特征 事件类扩展点 SpringApplicationRunListener
继承关系实现 ApplicationListener独立接口,不继承任何事件接口
触发方式被动接收事件广播主动调用(由 SpringApplication 直接触发)
设计模式观察者模式模板方法模式
注册方式通过 Spring Bean 或 SPI仅限 SPI(META-INF/spring.factories)
2). 源码证明

在 Spring Boot 核心源码中:
  1. public class SpringApplication { public ConfigurableApplicationContext run(String... args) { // 直接调用 RunListener 而非事件机制 listeners.starting(bootstrapContext, this.mainApplicationClass); listeners.environmentPrepared(...); // ... } }
复制代码
这明确展示了主动调用的模板方法模式。
2、SpringApplicationRunListener 三重身份

1). 本质:非事件类扩展点


  • 实现的是程序化调用契约而非事件监听契约
  • 在 Spring 事件系统初始化之前执行(ApplicationStartingEvent 就是由它发出的)
2). 角色:事件机制的触发器

核心实现类 EventPublishingRunListener:
  1. public class EventPublishingRunListener implements SpringApplicationRunListener { @Override public void starting(...) { // 它负责发布第一个事件 multicastEvent(new ApplicationStartingEvent(...)); } }
复制代码
这是 Spring Boot 事件体系的引擎启动器
3). 作用:完成 启动生命周期 全流程 的 编排

控制启动阶段流转:
  1. sequenceDiagram SpringApplication->>RunListener: starting() RunListener->>EventSystem: 发布ApplicationStartingEvent SpringApplication->>RunListener: environmentPrepared() RunListener->>EventSystem: 发布EnvironmentPreparedEvent
复制代码
3、与事件类扩展点的互动关系

5.png


  • ▶️ 紫色:SpringApplicationRunListener(非事件类)


来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册