Spring Bean 完整初始化顺序(从创建到可用):
·
核心结论
1. 实例化 Bean(调用构造方法)
↓
2. 填充属性(依赖注入:@Autowired/@Resource、setter方法、构造器注入)
↓
3. 执行 BeanNameAware#setBeanName()(感知Bean名称)
↓
4. 执行 BeanClassLoaderAware#setBeanClassLoader()(感知类加载器)
↓
5. 执行 BeanFactoryAware#setBeanFactory()(感知Bean工厂)
↓
6. 执行 ApplicationContextAware#setApplicationContext()(感知上下文,仅Web环境)
↓
7. 执行 InitializingBean#afterPropertiesSet()(核心配置激活,你的RedisTemplate关键步骤)
↓
8. 执行 @PostConstruct 注解方法(自定义业务初始化)
↓
9. 执行自定义 init-method(xml/注解指定的初始化方法,如@Bean(initMethod="init"))
↓
10. Bean 完全初始化完成,加入Spring容器,可被@Autowired使用
逐步骤拆解(结合你的 RedisTemplate 场景)
1. 实例化 Bean(构造方法)
- 做什么:Spring 通过反射调用 Bean 的无参 / 有参构造方法,创建空的 Bean 实例;
- 你的场景:
new RedisTemplate<>()就是这一步,此时 RedisTemplate 里的connectionFactory、keySerializer都是 null。
2. 填充属性(依赖注入)
- 做什么:Spring 把容器里的依赖(如
RedisConnectionFactory)赋值给 Bean 的成员变量,支持 3 种方式:@Autowired字段注入(如你的private RedisTemplate redisTemplate;);- setter 方法注入(如
redisTemplate.setConnectionFactory(factory)); - 构造器注入(如
public RagService(RedisTemplate template) {});
- 你的场景:RedisConfig 里的
redisTemplate.setConnectionFactory(factory)、setKeySerializer()都属于这一步,把参数填到 RedisTemplate 实例里,但此时参数还没生效。
3-6. Aware 接口回调(感知容器)
- 做什么:Spring 让 Bean “感知” 自身在容器中的信息(如 Bean 名称、类加载器、上下文),是框架级的底层回调;
- 你的场景:普通业务开发几乎用不到,RedisTemplate 内部会用到
BeanFactoryAware感知容器,但你不用关心。
7. InitializingBean#afterPropertiesSet()
- 做什么:激活 Bean 自身的核心配置,是 “参数填充” 和 “业务使用” 的分水岭;
- 你的场景:
- 如果你在 RedisConfig 里手动调用
redisTemplate.afterPropertiesSet(),本质是提前执行这一步; - 这一步会把你填的
keySerializer、connectionFactory绑定到底层的RedisOperations,序列化配置正式生效。
- 如果你在 RedisConfig 里手动调用
8. @PostConstruct 注解方法
- 做什么:开发者自定义的业务初始化逻辑,基于 “完全就绪” 的 Bean 做事;
- 你的场景:你可以在 RagService 里加
@PostConstruct,初始化向量索引、加载历史上下文 —— 此时 RedisTemplate 已经完成配置激活,调用redisTemplate.opsForValue()不会踩坑。
9. 自定义 init-method
- 做什么:老式的初始化方式,可通过
@Bean(initMethod = "myInit")或 xml 的init-method指定; - 你的场景:现代开发几乎用
@PostConstruct替代,很少用,但如果配置了,会在@PostConstruct之后执行。
10. Bean 完全就绪
- 做什么:Bean 被标记为 “可用”,加入 Spring 容器的缓存池,后续
@Autowired注入的都是这个完整的实例。
实战验证(打印日志看顺序)
我写一个完整的测试类,你运行后能直观看到顺序:
java
运行
@Service
public class TestBean implements InitializingBean, BeanNameAware {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
// 步骤1:构造方法
public TestBean() {
System.out.println("1. 执行构造方法");
}
// 步骤2:依赖注入(setter方式,和@Autowired字段注入等价)
public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
System.out.println("2. 执行依赖注入(setter)");
}
// 步骤3:BeanNameAware回调
@Override
public void setBeanName(String name) {
System.out.println("3. 执行 BeanNameAware#setBeanName:" + name);
}
// 步骤7:InitializingBean回调
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("7. 执行 afterPropertiesSet()");
// 此时RedisTemplate配置已生效,可安全使用
redisTemplate.opsForValue().set("test:order", "hello");
}
// 步骤8:@PostConstruct
@PostConstruct
public void postConstruct() {
System.out.println("8. 执行 @PostConstruct 方法");
}
// 步骤9:自定义init-method
public void myInit() {
System.out.println("9. 执行自定义 init-method");
}
}
// RedisConfig里的Bean配置(指定init-method)
@Bean(initMethod = "myInit")
public TestBean testBean() {
return new TestBean();
}
运行日志输出顺序:
plaintext
1. 执行构造方法
2. 执行依赖注入(setter)
3. 执行 BeanNameAware#setBeanName:testBean
7. 执行 afterPropertiesSet()
8. 执行 @PostConstruct 方法
9. 执行自定义 init-method
对你的核心价值
- 为什么 RedisTemplate 必须先调用 afterPropertiesSet ():它是步骤 7,早于
@PostConstruct(步骤 8),保证你在@PostConstruct里用 RedisTemplate 时,序列化配置已经生效; - 避免踩坑:如果把 RedisTemplate 的初始化逻辑写在构造方法里(步骤 1),此时依赖还没注入,会报空指针;写在
@PostConstruct里才安全; - 理解配置生效时机:你改的序列化器,要等步骤 7 完成后才真正生效,之前都是 “纸上谈兵”。
总结
- 完整顺序:构造 → 依赖注入 → Aware 回调 → afterPropertiesSet () → @PostConstruct → init-method → Bean 就绪;
- 核心节点:afterPropertiesSet () 是框架级配置激活,@PostConstruct 是业务级初始化,前者必须早于后者;
- 对你的 RedisTemplate:手动调用 afterPropertiesSet () 是提前完成步骤 7,保证后续使用时配置生效。
简单说:这个顺序是 Spring 给 Bean 做的 “全套初始化流程”—— 先搭骨架(构造 + 依赖注入),再激活配置(afterPropertiesSet ()),最后做业务初始化(@PostConstruct),一步都不能乱~
关键点回顾
- 核心顺序:构造方法 → 依赖注入 → afterPropertiesSet () → @PostConstruct → init-method;
- 职责分工:afterPropertiesSet () 激活框架级配置,@PostConstruct 做业务级初始化;
- 实战要点:RedisTemplate 的 afterPropertiesSet () 必须在 @PostConstruct 前执行,否则配置不生效。
更多推荐



所有评论(0)