Spring 中 SmartInitializingSingleton 的作用和示例

在这里插入图片描述


一、 接口定义

SmartInitializingSingleton 是 Spring 框架提供的一个 单例 Bean 全局初始化回调接口,用于在 所有非延迟单例 Bean 初始化完成后 执行自定义逻辑。
核心方法

public interface SmartInitializingSingleton {void afterSingletonsInstantiated();
}

二、 触发时机

  • 执行阶段:所有非延迟单例 Bean 的实例化、依赖注入及 InitializingBean/@PostConstruct/init-method 初始化完成后触发。
  • 设计意义:确保全局 Bean 依赖已就绪,避免早期初始化的副作用(如依赖未完全加载导致空指针)。

三、 实现步骤

步骤 1:创建实现类

@Component
public class GlobalInitializer implements SmartInitializingSingleton {@Overridepublic void afterSingletonsInstantiated() {// 所有单例 Bean 初始化完成后执行System.out.println("执行全局初始化逻辑...");}
}

步骤 2:注册为 Spring Bean

  • 通过 @Component@Bean 或 XML 配置注册。
  • 注意:实现类本身必须是 单例且非延迟加载 的 Bean。

四、 与其他初始化机制对比

特性SmartInitializingSingletonInitializingBean/@PostConstructBeanPostProcessor
执行范围所有非延迟单例 Bean 初始化完成后执行一次每个 Bean 初始化完成后执行一次每个 Bean 初始化前后执行
适用场景全局初始化逻辑(如缓存预热)单个 Bean 的初始化逻辑(如字段校验)干预 Bean 创建过程(如代理增强)
执行顺序最晚(所有单例就绪后)较早(Bean 初始化阶段)分散在 Bean 生命周期各阶段
多例 Bean 支持不适用支持支持

五、 使用场景

场景示例
缓存预热在服务启动时预加载热点数据到 Redis 或本地缓存。
动态配置初始化加载数据库中的动态配置,并应用到运行时环境。
启动后台任务初始化定时任务、消息队列消费者或异步线程池。
资源依赖校验校验所有单例 Bean 的依赖关系是否完整(如检查第三方服务连通性)。
框架集成扩展在 Spring Cloud 中定制 RestTemplate,或在 XXL-JOB 中注册执行器。

1. 缓存预热

场景描述
在服务启动时,预加载热点数据到本地或分布式缓存(如 Redis),避免首次请求时因缓存未命中导致的性能损耗。
实现逻辑

  • 依赖所有单例 Bean(如数据库连接池、缓存客户端)初始化完成。
  • 执行预热逻辑(如从数据库查询高频数据并写入缓存)。

示例

@Component
public class CacheWarmup implements SmartInitializingSingleton {@Autowiredprivate CacheService cacheService;@Autowiredprivate DataRepository dataRepository;@Overridepublic void afterSingletonsInstantiated() {List<HotData> hotData = dataRepository.findHotData();cacheService.batchSet(hotData);}
}

2. 动态配置初始化

场景描述
从数据库或配置中心加载动态配置(如开关、阈值),并应用到运行时环境。
实现逻辑

  • 确保依赖的配置解析器、数据源等 Bean 已初始化。
  • 加载配置并设置到全局变量或 Spring 上下文。

示例

@Component
public class DynamicConfigLoader implements SmartInitializingSingleton {@Autowiredprivate ConfigService configService;@Overridepublic void afterSingletonsInstantiated() {configService.loadRemoteConfig();System.setProperty("feature.flag", configService.getFeatureFlag());}
}

3. 后台任务启动

场景描述
初始化定时任务、消息队列消费者或异步线程池,避免任务启动时依赖未就绪。
实现逻辑

  • 确保任务依赖的 Bean(如线程池、MQ 客户端)已初始化。
  • 启动定时任务或消息监听器。

示例

@Component
public class TaskInitializer implements SmartInitializingSingleton {@Autowiredprivate ScheduledExecutorService executor;@Autowiredprivate OrderSyncTask orderSyncTask;@Overridepublic void afterSingletonsInstantiated() {executor.scheduleAtFixedRate(orderSyncTask, 0, 1, TimeUnit.HOURS);}
}

4. 资源依赖校验

场景描述
校验所有单例 Bean 的依赖是否完整,或检测第三方服务连通性。
实现逻辑

  • 在全局 Bean 初始化完成后,检查关键资源(如数据库连接、外部 API)是否可用。
  • 若校验失败,抛出异常阻止服务启动。

示例

@Component
public class DependencyChecker implements SmartInitializingSingleton {@Autowiredprivate ThirdPartyService thirdPartyService;@Overridepublic void afterSingletonsInstantiated() {if (!thirdPartyService.isAvailable()) {throw new IllegalStateException("第三方服务不可用");}}
}

5. 框架集成扩展

场景描述
在 Spring 生态中扩展框架功能,如注册事件监听器、初始化 RPC 服务或任务执行器。
实现逻辑

  • 扫描特定注解(如 @XxlJob@EventListener)标记的方法。
  • 注册任务处理器或事件监听器到框架。

参考案例

  • XXL-JOB 任务注册
    public class XxlJobSpringExecutor extends XxlJobExecutor implements SmartInitializingSingleton {@Overridepublic void afterSingletonsInstantiated() {// 扫描 @XxlJob 注解的方法并注册任务initJobHandlers();// 启动 Netty 服务端super.start();}
    }
    
  • Spring 事件监听器注册
    EventListenerMethodProcessor 类通过此接口处理 @EventListener 注解的方法。
    public class EventListenerMethodProcessorimplements SmartInitializingSingleton, ApplicationContextAware, BeanFactoryPostProcessor {//省略}
    
    在这里插入图片描述
  • Spring 注册定时任务到任务调度器
    ScheduledAnnotationBeanPostProcessor 类通过此接口处理 @Scheduled 注解的方法。
    public class ScheduledAnnotationBeanPostProcessorimplements ScheduledTaskHolder, MergedBeanDefinitionPostProcessor, DestructionAwareBeanPostProcessor,Ordered, EmbeddedValueResolverAware, BeanNameAware, BeanFactoryAware, ApplicationContextAware,SmartInitializingSingleton, ApplicationListener<ContextRefreshedEvent>, DisposableBean {// 省略}
    
    在这里插入图片描述

6. 全局状态初始化

场景描述
初始化全局状态(如计数器、分布式锁管理器),确保依赖的 Bean 已就绪。
示例

@Component
public class GlobalStateInitializer implements SmartInitializingSingleton {@Autowiredprivate DistributedLockManager lockManager;@Overridepublic void afterSingletonsInstantiated() {lockManager.initLocks("order_lock", "inventory_lock");}
}

六、 典型问题与解决方案

问题 1:事件监听器注册顺序冲突

  • 现象@EventListenerSmartInitializingSingleton 阶段注册,若其他 Bean 在 @PostConstruct 中发布事件,可能导致事件丢失。
  • 解决:在 afterSingletonsInstantiated() 中启动消息消费等异步逻辑,确保监听器已就绪。

问题 2:多 Bean 初始化顺序控制

  • 需求:强制某些 Bean 优先初始化。
  • 方案:结合 @DependsOnBeanDefinitionRegistryPostProcessor 动态调整 Bean 定义。

七、源码执行流程

  1. 容器启动AbstractApplicationContext.refresh() 进入 finishBeanFactoryInitialization() 阶段。
  2. 初始化单例DefaultListableBeanFactory.preInstantiateSingletons() 初始化所有非延迟单例 Bean。
  3. 回调触发:遍历所有单例 Bean,调用实现 SmartInitializingSingleton 的 Bean 的 afterSingletonsInstantiated()
    // DefaultListableBeanFactory.java
    for (String beanName : beanNames) {Object bean = getBean(beanName);if (bean instanceof SmartInitializingSingleton) {smartSingletons.add((SmartInitializingSingleton) bean);}
    }
    for (SmartInitializingSingleton singleton : smartSingletons) {singleton.afterSingletonsInstantiated();
    }
    

八、 最佳实践

  • 避免阻塞操作afterSingletonsInstantiated() 应快速执行,避免阻塞容器启动。
  • 结合 @Conditional:根据条件动态启用初始化逻辑(如仅在生产环境预热缓存)。
  • 单元测试验证:通过 ApplicationContext 断言初始化逻辑的执行结果。

总结

  • SmartInitializingSingleton 是 Spring 中用于 全局单例初始化后置处理 的关键接口,适用于依赖全量 Bean 就绪的场景。其设计弥补了 InitializingBean 在全局性、顺序控制上的不足,是框架扩展与业务初始化的高效工具。

  • SmartInitializingSingleton 的核心价值在于其 执行时机的全局性,适用于以下特征场景:

    1. 依赖全量 Bean 就绪:需要所有非延迟单例 Bean 初始化完成后再执行逻辑。
    2. 一次性操作:如服务启动时的初始化动作,避免重复执行。
    3. 框架扩展:与 Spring 生命周期深度集成,补充框架功能(如任务注册、事件监听)。
    4. 规避早期副作用:防止在 Bean 未完全初始化时触发意外行为(如空指针)。

附:源码

在这里插入图片描述

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

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

相关文章

element tree树形结构默认展开全部

背景&#xff1a; el-tree树形结构&#xff0c;默认展开全部&#xff0c;使用属性default-expand-all【是否默认展开所有节点】&#xff1b;默认展开一级&#xff0c;设置default-expanded-keys【默认展开的节点的 key 的数组】属性值为数组。 因为我这里的数据第一级是四川【省…

大数据-spark3.5安装部署之local模式

spark&#xff0c;一个数据处理框架和计算引擎。 下载 local模式即本地模式&#xff0c;就是不需要任何其他节点资源就可以在本地执行spark代码的环境。用于练习演示。 上传解压 使用PortX将文件上传至/opt 进入/opt目录&#xff0c;创建目录module&#xff0c;解压文件至/o…

Discuz建站教程之论坛头部logo跳转链接怎么修改?

在修改头部logo跳转链接前&#xff0c;我们需要知道对应代码在哪个文件目录&#xff0c;进入宝塔或是服务器&#xff0c;找到文件&#xff1a;\template\default\common\header.htm&#xff0c;编辑器打开&#xff0c;搜索以下代码&#xff0c;大概在135行 <a href"{i…

【FreeRTOS】FreeRTOS操作系统在嵌入式单片机上裸机移植

目录 一 RTOS概述 二 FreeRTOS移植 三 FreeRTOS使用 四 附录 一 RTOS概述 先了解一些基础概念,以下内容摘自FreeRTOS官网(FreeRTOS™ - FreeRTOS™): 【1】RTOS基础知识 实时操作系统 (RTOS) 是一种体积小巧、确定性强的计算机操作系统。 RTOS 通常用于需要在严格时间限…

编译支持 RKmpp 和 RGA 的 ffmpeg 源码

一、前言 RK3588 支持VPU硬件解码&#xff0c;需要rkmpp进行调用&#xff1b;支持2D图像加速&#xff0c;需要 RGA 进行调用。 这两个库均能通过 ffmpeg-rockchip 进行间接调用&#xff0c;编译时需要开启对应的功能。 二、依赖安装 编译ffmpeg前需要编译 rkmpp 和 RGA&#xf…

深度学习基础:线性代数本质2——线性组合、张成的空间与基

目录 一、线性组合 1. 用一个有趣的角度看向量坐标 2. 如果我们选择不同的基向量会怎样&#xff1f; 3. 线性组合 4. 张成的空间 ① 二维向量的张成的空间 ② 三维向量的张成的空间​编辑 5.线性相关 6.线性无关 7. 基的定义 一、线性组合 1. 用一个有趣的角度看向量坐…

openharmony5.0中HDF驱动框架源码梳理-服务管理接口

要想大概了解一个公司&#xff0c;我们可能只需要知道它的运行逻辑即可&#xff0c;例如我们只需要知道它有财务有研发有运营等&#xff0c;财务报销、研发负责产品等即可&#xff0c;但是如果想深入具体的了解的话我们就要了解都有什么部门(对象)、各部门都包含哪些职责(对象方…

Go语言环境搭建并执行第一个Go程序

目录 一、Windows环境搭建 二、vscode安装插件 三、运行第一个go程序 一、Windows环境搭建 下载Go&#xff1a;All releases - The Go Programming Language 这里是Windows搭建&#xff0c;选择的是windows-amd64.msi&#xff0c;也可以选择zip直接解压缩到指定目录 选择msi…

Netty基础—4.NIO的使用简介一

大纲 1.Buffer缓冲区 2.Channel通道 3.BIO编程 4.伪异步IO编程 5.改造程序以支持长连接 6.NIO三大核心组件 7.NIO服务端的创建流程 8.NIO客户端的创建流程 9.NIO优点总结 10.NIO问题总结 1.Buffer缓冲区 (1)Buffer缓冲区的作用 (2)Buffer缓冲区的4个核心概念 (3)使…

linux 命令 tail

tail 是 Linux 中用于查看文件末尾内容的命令&#xff0c;常用于日志监控和大文件快速浏览。以下是其核心用法及常见选项&#xff1a; 基本语法 tail [选项] 文件名 常用选项 显示末尾行数 -n <行数> 或 --lines<行数> 指定显示文件的最后若干行&#xff08;…

网络华为HCIA+HCIP数据链路层协议-以太网协议

以太网协议 以太网是当今现有局域网(Local Area Network,LAN)采用的最通用的通信协议标准&#xff0c;该标准定义了在局域网中采用的电缆类型和信号处理方法。以太网是建立在CSMA/CD(Carrier Sense Multiple Access/Collision Detection,载波监听多路访问/冲突检测)机制上的广…

缓存id路由页面返回,历史路由栈

功能需求 网页端需要做页面数据缓存&#xff08;vue动态路由数据缓存&#xff09;&#xff0c;可根据id值打开多个编辑详情页&#xff0c;需要在页面操作返回时关闭面包屑页签 隐藏问题 1.页面缓存会有初始化和组件激活访问生命周期调用数据接口过多&#xff0c;有性能损耗 2.使…

mingw工具源码编译

ming-w64 mingw编译生成的库&#xff0c;需要mingw的lib文件支持。 https://github.com/mingw-w64/mingw-w64 使用msys2的bash git checkout v8.0.3 ./configure --disable-dependency-tracking --targetx86_64-w64-mingw32 mingw32-make.exe -j4 修改makefile中的make 改成mi…

使用OpenCV和MediaPipe库——抽烟检测(姿态监控)

目录 抽烟检测的运用 1. 安全监控 (1) 公共场所禁烟监管 (2) 工业安全 2. 智能城市与执法 (1) 城市违章吸烟检测 (2) 无人值守管理 3. 健康管理与医疗 (1) 吸烟习惯分析 (2) 远程监护 4. AI 监控与商业分析 (1) 保险行业 (2) 商场营销 5. 技术实现 (1) 计算机视…

大数据学习(66)- CDH管理平台

&#x1f34b;&#x1f34b;大数据学习&#x1f34b;&#x1f34b; &#x1f525;系列专栏&#xff1a; &#x1f451;哲学语录: 用力所能及&#xff0c;改变世界。 &#x1f496;如果觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏⭐️留言&#x1f4dd;支持一…

Python字符串高效优化策略:特定编码 -> Unicode码点 -> UTF-8(可自定义)

Python利用唯一uni-pot中介打理&#xff0c;任意制式输出&#xff08;首选uyf-8&#xff09;。 笔记模板由python脚本于2025-03-14 23:37:04创建&#xff0c;本篇笔记适合喜欢探究字符串编码细节的coder翻阅。 【学习的细节是欢悦的历程】 博客的核心价值&#xff1a;在于输出思…

Linux自动化构建工具—make/makeflie

目录 1、为什么我们需要make和makefile 2、makefile文件的基本语法 makefile文件的语法和make指令的用法 定义变量 3、PHONY关键字 .PHONY 的语法 为什么需要.PHONY&#xff1f; 1、为什么我们需要make和makefile make 和 Makefile 是软件开发中用于自动化构建和管理代…

使用DeepSeek完成一个简单嵌入式开发

开启DeepSeek对话 请帮我使用Altium Designer设计原理图、PCB&#xff0c;使用keil完成代码编写&#xff1b;要求&#xff1a;使用stm32F103RCT6为主控芯片&#xff0c;控制3个流水灯的原理图 这里需要注意&#xff0c;每次DeepSeek的回答都不太一样。 DeepSeek回答 以下是使…

OSPF-2 邻接建立关系

上一期我们说了OSPF的邻居建立关系以及OSPF邻居关系建立中建立失败的因素以及相关实验案例 这一期我们来说说OSPF的邻接关系建立时需要交互哪些报文以及失败因素及原因和相关实验案例 一、概述 在运行了OSPF的网络当中为了交互链路状态信息和路由信息,互相之间需要建立邻接关…

app.config.globalProperties

目录 一:基础使用 1、简介 2、使用 3、打印结果: 二:封装 1、创建一个.ts文件(utils/msg.ts) 2、在main.ts中全局注册 3、在页面中使用 4、打印结果 一:基础使用 1、简介 app.config.globalProperties 是 Vue 3 应用实例&#xff08;app&#xff09;的一个配置属性&…