Spring相关知识

bean生命周期

好的 👍 我给你梳理一下 Spring Bean 的生命周期,并且标注出每个阶段大概会发生什么。


🌱 Spring Bean 生命周期

一个 Bean 从创建到销毁,大致会经过以下几个阶段:

1. 实例化 (Instantiation)

  • Spring 根据 配置(XML/注解/JavaConfig),使用反射创建 Bean 的实例。
  • 这时还只是一个"空壳对象",属性还没被赋值。

2. 属性赋值 (Populate Properties)

  • Spring 进行 依赖注入(DI),将需要的依赖(其他 Bean、配置值等)注入到 Bean 中。
  • 这一步会执行 setter 方法或构造函数注入。

3. BeanNameAware / BeanFactoryAware 等回调

  • 如果 Bean 实现了某些 Aware 接口,Spring 会回调这些方法:

    • BeanNameAware.setBeanName():告诉 Bean 它在容器中的名字。
    • BeanFactoryAware.setBeanFactory():告诉 Bean 它的 BeanFactory。
    • ApplicationContextAware.setApplicationContext():告诉 Bean 它的 ApplicationContext。

4. BeanPostProcessor - 前置处理

  • Spring 会调用 BeanPostProcessor.postProcessBeforeInitialization()
  • 常用于对 Bean 进行一些额外加工,比如自动代理(AOP 的核心就是这里介入)。

5. 初始化 (Initialization)

  • 如果 Bean 实现了 InitializingBean 接口,会调用 afterPropertiesSet() 方法。
  • 如果在配置中指定了 init-method,会调用对应的方法。
  • 这是 Bean 完全就绪前的最后一步初始化逻辑。

6. BeanPostProcessor - 后置处理

  • Spring 会调用 BeanPostProcessor.postProcessAfterInitialization()
  • 在这里可以对 Bean 进行增强(比如 AOP 代理生成就在这一步)。

7. Bean 就绪 (Ready for use)

  • 到这里,Bean 就可以被应用程序使用了。
  • Spring IoC 容器中的 Bean 通常是 单例,整个容器中共享一份。

8. 销毁 (Destruction)

  • 当容器关闭时:

    • 如果 Bean 实现了 DisposableBean ,会调用 destroy() 方法。
    • 如果配置了 destroy-method,也会被调用。
  • 这一步主要用于释放资源(关闭连接、线程池等)。


🔄 总结成一个流程图

复制代码
实例化 → 属性注入 → Aware回调 → 前置处理 → 初始化 → 后置处理 → 就绪使用 → 销毁

我之前一直觉得,初始化就是对对象进行赋值和相关准备逻辑。这里属性注入,似乎也是属性的赋值,所以我才一直觉得是属性注入归于初始化

👌 你这个理解其实很自然,很多人都会混淆。

因为"初始化"这个词在日常语境里确实包含"给属性赋值"+"准备逻辑"两方面。

但是在 Spring 框架里,它做了更细粒度的拆分:


🏗️ Spring 的划分逻辑

Spring 把 Bean 生命周期拆开,是为了 更好地给开发者介入点

  • 实例化 (Instantiation)

    👉 new 一个对象,还没属性。

  • 属性注入 (Populate Properties)

    👉 Spring 把依赖(配置值、其他 Bean)"填充"进去。

    (相当于"把材料和家具搬进房子")

  • 初始化 (Initialization)

    👉 Spring 通知 Bean:"你的依赖已经准备好了,你可以开始做额外逻辑了"。

    (比如检查依赖是否齐全、启动资源连接、预热缓存等)

    • InitializingBean.afterPropertiesSet()
    • @PostConstruct
    • init-method

🏡 打个比喻

想象你装修一套房子:

  1. 实例化:建好房子的毛坯结构。
  2. 属性注入:把家具、电器都搬进房子。
  3. 初始化:开通水电,安装 WiFi,调试一下确保能正常住人。

如果不分开,框架就很难在合适的时机让你"介入",也就没有 @PostConstruct 这些钩子了。


📌 关键点

  • Java 面向对象角度看:给对象赋值,当然可以叫初始化。

  • Spring 语义看:

    • 属性注入 = 依赖赋值。
    • 初始化 = 注入完成后,执行额外的准备逻辑。

BeanPostProcessor.postProcessBeforeInitialization()。为什么这里都是BeanPostProcessor,这里既然分为前置处理和后置处理,那么应该叫做BeanProcessor才对

👍 你抓住了一个关键点。

确实,从直觉上看:

  • postProcessBeforeInitialization()
  • postProcessAfterInitialization()

既然有"前置"和"后置",名字里却写着 Post (后置),好像应该叫 BeanProcessor 才对。


🔍 为什么叫 BeanPostProcessor

这是因为 Spring 的命名习惯 和它的生命周期设计有关。

  1. 不是处理 Bean 的创建过程,而是处理 Bean 创建之后的过程

    • BeanPostProcessor 只会在 Bean 实例化 + 属性注入完成之后 才介入。
    • 它不会参与 new Bean() 或依赖注入的环节。
    • 所以它处理的逻辑都属于 "Bean 已经创建完了(post-creation)" 的范围。
  2. "BeforeInitialization / AfterInitialization" 只是两个切点

    • Spring 定义的 "Initialization" = 执行初始化回调 (如 @PostConstructafterPropertiesSet())。
    • postProcessBeforeInitialization():在初始化方法 调用之前 介入。
    • postProcessAfterInitialization():在初始化方法 调用之后 介入。
    • 但二者都还是在 Bean 创建之后 (post) 的逻辑,所以统称 BeanPostProcessor
  3. 历史兼容性

    • Spring 早期就把这个接口叫做 BeanPostProcessor
    • 后来虽然扩展出 "before / after" 两个切点,但为了不破坏兼容性,保持了原名。

🏗️ 小结

  • BeanPostProcessor 之所以叫 Post ,是因为它处理的时机在 Bean 实例化 + 属性注入之后
  • 它不会介入 Bean 的"构造"过程,而只处理"后加工"阶段。
  • "before / after" 指的是 初始化方法的前后,不是指 Bean 创建的前后。

👉 换句话说:
BeanPostProcessor = Bean 创建完成后的加工器

  • BeforeInitialization → 初始化回调前
  • AfterInitialization → 初始化回调后

这里实例化后,之前的一些操作是什么,都讲解一下

我看了一下你发的这个图 👍,它分成了 Spring 容器启动流程Bean 创建流程 。你问的"实例化之前的一些操作",就是在 实例化 (new 对象) 之前,Spring 容器对 Bean 要做的一系列准备。

我逐个解释一下图里的步骤(重点在实例化之前的环节):


🌱 容器启动阶段(ApplicationContext)

  1. 启动 ApplicationContext

    • 你调用 new ClassPathXmlApplicationContext()AnnotationConfigApplicationContext() 的时候,Spring 容器启动。
  2. 创建 BeanFactory

    • ApplicationContext 内部其实是基于 DefaultListableBeanFactory
    • BeanFactory 是最底层的 IoC 容器,负责管理 Bean 的注册和获取。
  3. 初始化 BeanFactory

    • 为 BeanFactory 设置一些必要的组件,比如 BeanPostProcessorBeanFactoryPostProcessor 等。
  4. 执行 BeanFactory 后置处理器

    • 扫描、解析配置(XML/注解)就是在这里进行的。
    • 例如:ConfigurationClassPostProcessor 会去扫描 @Configuration@ComponentScan,把类信息解析成 BeanDefinition
  5. 生成 BeanDefinition

    • 扫描结果(类信息)被转换成 BeanDefinition ,注册到 BeanFactory 的 beanDefinitionMap 里。
    • 这里还没有 new Bean,只是"元数据"。

🌱 Bean 创建流程(实例化之前)

当容器要创建一个具体 Bean 时,流程是:

  1. 合并 BeanDefinition

    • 如果有父 BeanDefinition(继承关系)、注解/配置合并,Spring 会在这里整合成一个完整的定义。
  2. 加载类 (Load Class)

    • 根据 BeanDefinition 里的 className,反射加载对应的 Class 对象。
  3. 实例化前(Instantiation Aware)

    • 在真正 new 对象之前,Spring 会先调用一些 InstantiationAwareBeanPostProcessor

    • 比如:

      • 判断是否需要用代理类替代原始类(AOP 在这一步可能就决定走代理工厂)。
      • 也可以在这里"短路",直接返回一个代理 Bean,而不是走普通的构造函数。
  4. 推断构造方法

    • Spring 会判断用哪个构造方法来实例化:

      • 默认无参构造
      • @Autowired 的构造
      • 或者最匹配的构造函数

📌 然后才是 实例化 (new)

  • 选定构造方法后,用反射创建对象 → 才进入你问的"实例化"阶段。

✅ 总结

实例化之前,主要做了这些事:

  1. 准备 BeanDefinition(配置扫描、合并)。
  2. 加载 class 对象。
  3. 调用 InstantiationAwareBeanPostProcessor → 机会点:是否要直接返回代理对象。
  4. 推断用哪个构造方法。

才会执行 实例化 (new)