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

Spring 中 SmartInitializingSingleton 的作用和示例

在这里插入图片描述


一、 接口定义

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

public interface SmartInitializingSingleton {
    void afterSingletonsInstantiated();
}

二、 触发时机

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

三、 实现步骤

步骤 1:创建实现类

@Component
public class GlobalInitializer implements SmartInitializingSingleton {
    @Override
    public 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 {
    @Autowired
    private CacheService cacheService;
    @Autowired
    private DataRepository dataRepository;

    @Override
    public void afterSingletonsInstantiated() {
        List<HotData> hotData = dataRepository.findHotData();
        cacheService.batchSet(hotData);
    }
}

2. 动态配置初始化

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

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

示例

@Component
public class DynamicConfigLoader implements SmartInitializingSingleton {
    @Autowired
    private ConfigService configService;

    @Override
    public void afterSingletonsInstantiated() {
        configService.loadRemoteConfig();
        System.setProperty("feature.flag", configService.getFeatureFlag());
    }
}

3. 后台任务启动

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

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

示例

@Component
public class TaskInitializer implements SmartInitializingSingleton {
    @Autowired
    private ScheduledExecutorService executor;
    @Autowired
    private OrderSyncTask orderSyncTask;

    @Override
    public void afterSingletonsInstantiated() {
        executor.scheduleAtFixedRate(orderSyncTask, 0, 1, TimeUnit.HOURS);
    }
}

4. 资源依赖校验

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

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

示例

@Component
public class DependencyChecker implements SmartInitializingSingleton {
    @Autowired
    private ThirdPartyService thirdPartyService;

    @Override
    public void afterSingletonsInstantiated() {
        if (!thirdPartyService.isAvailable()) {
            throw new IllegalStateException("第三方服务不可用");
        }
    }
}

5. 框架集成扩展

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

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

参考案例

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

6. 全局状态初始化

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

@Component
public class GlobalStateInitializer implements SmartInitializingSingleton {
    @Autowired
    private DistributedLockManager lockManager;

    @Override
    public 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 未完全初始化时触发意外行为(如空指针)。

附:源码

在这里插入图片描述

相关文章:

  • 无需微调的对齐方法URIAL
  • Android安全支付-整体架构-KeyStore2-APP到Framework层的调用
  • Vmware下的openEuler
  • Docker相关面试题
  • 算法沉淀五:位运算
  • 【Python 数据结构 15.哈希表】
  • JVM 2025/3/14
  • python-54-使用环境变量库python-dotenv进行应用程序配置参数的管理
  • 红色警戒2:共和国之辉红警语音台词是什么?
  • 【Vue.js】
  • docker python:latest镜像 允许ssh远程
  • VUE的脚手架搭建引入类库
  • 使用excel4node向excel批量写入图片
  • 2024 年第四届高校大数据挑战赛-赛题 A:岩石的自动鉴定
  • datax源码分析
  • 一个网络安全产品设计文档
  • Java高级-03.反射-获取构造器对象并使用
  • kali常用命令
  • Vue3使用ECharts入门示例
  • C++初阶——类和对象(一)
  • 俄乌直接谈判结束,乌称“毫无成果”
  • 自然资源部:不动产登记累计化解遗留问题房屋2000多万套
  • 男子恶意遗弃幼子获刑,最高法发布涉未成年人家庭保护典型案例
  • 齐白石精品在波士顿展出,“白石画屋”呈现水墨挥洒
  • 7月纽约举办“上海日”,上海大剧院舞剧《白蛇》连演三场
  • 文化润疆|为新疆青少年提供科普大餐,“小小博物家(喀什版)”启动