SmartInitializingSingleton 和 InitializingBean 的相同点和区别
这两个接口经常会被混淆,因为它们都和 Spring Bean 的初始化时机有关,但用途和触发时机不一样。
- InitializingBean:关注自己,属性注入完成就执行(仅针对当前 Bean)。
- SmartInitializingSingleton 关注全局,等所有单例初始化完成再执行(一次性全局触发。)
一. 相同点
| 方面 | 描述 |
|---|---|
| 都是 Spring Bean 生命周期回调接口 | 由 Spring 容器在特定时机调用,不需要手动调用。 |
| 都在 Bean 创建完成后 执行 | 都是 Spring Bean 初始化阶段的钩子方法,用于执行额外逻辑。 |
| 都是 非必需接口 | 实现与否完全取决于业务需要。 |
都可以配合 @PostConstruct 或 init-method 使用 | 属于同类的初始化扩展机制。 |
二. 区别
| 特性 | InitializingBean | SmartInitializingSingleton |
|---|---|---|
| 接口定义 | public interface InitializingBean { void afterPropertiesSet() throws Exception; } | public interface SmartInitializingSingleton { void afterSingletonsInstantiated(); } |
| 调用时机 | 在 当前 Bean 的所有属性填充完成(依赖注入完成)后立即调用 | 在 容器中所有单例 Bean 都初始化完成后调用(延迟到整个上下文准备就绪) |
| 粒度 | 作用于单个 Bean,一个 Bean 实现就只会在它自己初始化完成时调用一次 | 作用于全局单例 Bean 阶段,一个实现类的 Bean 会等所有单例都完成初始化后才调用一次 |
| 适用场景 | 用于 单个 Bean 的属性检查/初始化,例如验证配置、开启资源连接等 | 用于 依赖其他 Bean 完全初始化后的统一处理,例如批量注册、全局初始化依赖其他 Bean 的逻辑 |
| 是否依赖容器其他 Bean 完全就绪 | 否,只要求自身依赖就绪即可 | 是,必须等整个容器的单例初始化阶段结束 |
| 常见用法 | - 校验配置参数 - 初始化数据库连接/缓存等 | - 事件发布器初始化(需依赖所有 Listener) - 全局数据装载 - 注册与其他 Bean 交互的服务 |
三. 生命周期位置对比(简化版)
Spring Bean 初始化流程(单例)
实例化 Bean
↓
依赖注入
↓
调用 InitializingBean.afterPropertiesSet()
↓
@PostConstruct / init-method
↓
(对其他 Bean 重复以上流程,直到所有单例 Bean 都完成初始化)
↓
调用 SmartInitializingSingleton.afterSingletonsInstantiated()
↓
容器可用四.举个代码例子
java
@Component
public class MyBean implements InitializingBean {
@Override
public void afterPropertiesSet() {
System.out.println("MyBean 初始化完成(属性已注入)");
}
}
@Component
public class MySmartBean implements SmartInitializingSingleton {
@Override
public void afterSingletonsInstantiated() {
System.out.println("所有单例 Bean 都已初始化完成,MySmartBean 开始执行");
}
}运行输出:
text
MyBean 初始化完成(属性已注入)
所有单例 Bean 都已初始化完成,MySmartBean 开始执行