核心结论

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 里的 connectionFactorykeySerializer 都是 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(),本质是提前执行这一步;
    • 这一步会把你填的 keySerializerconnectionFactory 绑定到底层的 RedisOperations,序列化配置正式生效。
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

对你的核心价值

  1. 为什么 RedisTemplate 必须先调用 afterPropertiesSet ():它是步骤 7,早于 @PostConstruct(步骤 8),保证你在 @PostConstruct 里用 RedisTemplate 时,序列化配置已经生效;
  2. 避免踩坑:如果把 RedisTemplate 的初始化逻辑写在构造方法里(步骤 1),此时依赖还没注入,会报空指针;写在 @PostConstruct 里才安全;
  3. 理解配置生效时机:你改的序列化器,要等步骤 7 完成后才真正生效,之前都是 “纸上谈兵”。

总结

  1. 完整顺序:构造 → 依赖注入 → Aware 回调 → afterPropertiesSet () → @PostConstruct → init-method → Bean 就绪;
  2. 核心节点:afterPropertiesSet () 是框架级配置激活,@PostConstruct 是业务级初始化,前者必须早于后者;
  3. 对你的 RedisTemplate:手动调用 afterPropertiesSet () 是提前完成步骤 7,保证后续使用时配置生效。

简单说:这个顺序是 Spring 给 Bean 做的 “全套初始化流程”—— 先搭骨架(构造 + 依赖注入),再激活配置(afterPropertiesSet ()),最后做业务初始化(@PostConstruct),一步都不能乱~

关键点回顾

  1. 核心顺序:构造方法 → 依赖注入 → afterPropertiesSet () → @PostConstruct → init-method;
  2. 职责分工:afterPropertiesSet () 激活框架级配置,@PostConstruct 做业务级初始化;
  3. 实战要点:RedisTemplate 的 afterPropertiesSet () 必须在 @PostConstruct 前执行,否则配置不生效。
Logo

助力广东及东莞地区开发者,代码托管、在线学习与竞赛、技术交流与分享、资源共享、职业发展,成为松山湖开发者首选的工作与学习平台

更多推荐