Skip to content

Spring 的 Bean 的生命周期

约 1961 字大约 7 分钟

Spring框架美团

2025-07-03

⭐ 题目日期:

美团 - 2025/4/25

📝 题解:

Spring Bean 的生命周期指的是一个 Bean 从被创建、初始化、使用到最终被销毁的整个过程。Spring 容器(ApplicationContext)精细地管理着这个过程,并提供了多个扩展点允许开发者介入自定义逻辑。

以下是 Spring Bean 生命周期的详细阶段:

  1. Bean 定义 (BeanDefinition) 的加载与解析:

    • 容器启动时(如 ClassPathXmlApplicationContextAnnotationConfigApplicationContext 初始化),会读取配置文件(XML)、Java 配置类(@Configuration)或扫描注解(@ComponentScan)。
    • 找到的所有 Bean 定义(通常是 BeanDefinition 对象)被加载到容器内部。BeanDefinition 包含了创建 Bean 所需的所有元数据:类名、作用域(scope)、初始化方法、销毁方法、属性值、依赖关系等。
  2. 实例化 (Instantiation):

    • 根据 BeanDefinition 中指定的类名(Class),容器使用构造器(默认无参构造器,或指定的构造器)来创建 Bean 的一个实例
    • 此时只是简单地调用构造方法 new Xxx(),分配了内存空间,Bean 的属性都还是默认值(null0false 等),依赖也没有注入。
  3. 属性填充/依赖注入 (Population / Dependency Injection):

    • 容器根据 BeanDefinition 中的配置信息(如 property 标签、@Autowired@Value@Resource 等注解),将值或对其他 Bean 的引用设置(注入)到新创建的 Bean 实例的属性或字段中
    • 这是实现 IoC(控制反转)的核心步骤。
  4. Aware 接口回调 (Aware Interfaces Callbacks):

    • 如果 Bean 实现了 Spring 提供的各种 Aware 接口,容器会调用相应的方法,将相关的容器基础设施对象“通知”给 Bean。这是在属性注入之后,初始化回调之前执行的。
    • 常用 Aware 接口:
      • BeanNameAware: 设置 Bean 在容器中的名字 (setBeanName(String name))。
      • BeanFactoryAware: 设置创建该 Bean 的 BeanFactory 实例 (setBeanFactory(BeanFactory beanFactory))。提供对底层工厂的访问。
      • ApplicationContextAware: 设置创建该 Bean 的 ApplicationContext 实例 (setApplicationContext(ApplicationContext applicationContext))。提供对完整应用上下文的访问(包含 BeanFactory 的所有功能,还提供事件发布、资源加载等)。
      • EnvironmentAware: 设置应用环境 (Environment) 对象 (setEnvironment(Environment environment))。用于访问配置属性和 profiles。
      • ResourceLoaderAware: 设置资源加载器 (ResourceLoader) (setResourceLoader(ResourceLoader resourceLoader))。用于加载类路径或文件系统资源。
      • ApplicationEventPublisherAware: 设置事件发布器 (ApplicationEventPublisher) (setApplicationEventPublisher(ApplicationEventPublisher publisher))。用于发布应用事件。
      • MessageSourceAware: 设置国际化消息源 (MessageSource) (setMessageSource(MessageSource messageSource))。用于国际化。
  5. BeanPostProcessor 的前置处理 (postProcessBeforeInitialization):

    • 如果容器中存在实现了 BeanPostProcessor 接口的 Bean,容器会每个 Bean 的初始化回调方法(下一步)执行之前,调用所有 BeanPostProcessorpostProcessBeforeInitialization(Object bean, String beanName) 方法。
    • 开发者可以通过实现此接口,在 Bean 初始化前对 Bean 实例进行修改、包装(如 AOP 代理)或执行某些逻辑。这是一个强大的全局扩展点。
  6. 初始化回调 (Initialization Callbacks):

    • 容器调用 Bean 定义的初始化方法。有三种主要方式指定:
      • 实现 InitializingBean 接口: 实现 afterPropertiesSet() 方法。容器在属性注入完成后调用此方法。
      • XML 配置中指定 init-method 属性: 指定一个自定义的无参方法名。
      • 使用 @PostConstruct 注解: 标注在一个自定义的无参方法上。这是现代 Spring 应用推荐的方式。
    • 注意: 如果同时使用了多种方式,调用顺序是:
      1. @PostConstruct 注解的方法
      2. InitializingBean.afterPropertiesSet()
      3. 自定义的 init-method 指定的方法
    • 在此阶段,Bean 的属性已注入完毕,可以执行一些自定义的初始化逻辑,如验证配置、建立数据库连接、启动线程等。
  7. BeanPostProcessor 的后置处理 (postProcessAfterInitialization):

    • 如果容器中存在实现了 BeanPostProcessor 接口的 Bean,容器会每个 Bean 的初始化回调方法(上一步)执行之后,调用所有 BeanPostProcessorpostProcessAfterInitialization(Object bean, String beanName) 方法。
    • 这是另一个强大的全局扩展点。AOP 动态代理通常就是在这个阶段创建的。 开发者可以在这里对初始化完成的 Bean 进行最终处理或返回一个包装后的代理对象。
  8. Bean 就绪可用 (Ready for Use):

    • 经过以上所有步骤,Bean 已经完全初始化完毕,其属性已注入,初始化逻辑已执行,并可能已被后置处理器包装(如代理)。此时 Bean 被放入容器(通常是单例池,如果是单例作用域),等待应用程序通过容器获取 (getBean()) 并使用。
  9. 使用期 (In Use):

    • 应用程序通过容器获取 Bean 实例并使用其功能。这是 Bean 生命周期的核心阶段。
  10. 销毁回调 (Destruction Callbacks): (当容器关闭时触发)

    • 当 Spring 容器关闭时(如调用 ApplicationContextclose() 方法),对于实现了销毁逻辑的 Bean(通常是单例 Bean,原型 Bean 的销毁由调用者管理),容器会调用其定义的销毁方法。同样有三种主要方式指定:
      • 实现 DisposableBean 接口: 实现 destroy() 方法。
      • XML 配置中指定 destroy-method 属性: 指定一个自定义的无参方法名。
      • 使用 @PreDestroy 注解: 标注在一个自定义的无参方法上。推荐方式。
    • 注意: 如果同时使用了多种方式,调用顺序是:
      1. @PreDestroy 注解的方法
      2. DisposableBean.destroy()
      3. 自定义的 destroy-method 指定的方法
    • 在此阶段,Bean 应执行清理逻辑,如关闭数据库连接、停止线程、释放资源等。
  11. Bean 被垃圾回收 (Garbage Collection):

    • 容器关闭后,不再持有 Bean 的引用。Bean 实例及其占用的资源最终由 JVM 的垃圾回收器回收。

图解简化流程:

[容器启动]
   |
   V
加载 & 解析 BeanDefinition --> [Bean 定义注册]
   |
   V
实例化 (new) ----------------> Bean 对象(空壳,属性未注入)
   |
   V
属性填充/依赖注入 ------------> Bean 对象(属性已赋值,依赖已注入)
   |
   V
Aware 接口回调 -------------> Bean 对象(已获知容器信息)
   |
   V
BeanPostProcessor.postProcessBeforeInitialization() -> 可修改/增强 Bean
   |
   V
初始化回调 (@PostConstruct / afterPropertiesSet() / init-method) -> 执行自定义初始化
   |
   V
BeanPostProcessor.postProcessAfterInitialization() -> 可修改/增强 Bean (AOP 代理在此创建)
   |
   V
[Bean 就绪] -----------------> 放入容器,等待使用
   |
   V
应用程序使用 Bean
   |
   V
[容器关闭]
   |
   V
销毁回调 (@PreDestroy / destroy() / destroy-method) -> 执行自定义清理
   |
   V
[Bean 销毁,资源释放]
   |
   V
[JVM GC 回收]

关键点总结:

  • BeanPostProcessor 是全局性的: 它们影响容器中所有的 Bean。是实现 AOP、事务管理、自定义注解处理等高级功能的基础。
  • Aware 接口提供基础设施访问: 让 Bean 感知到容器环境。
  • 初始化回调 (@PostConstruct 等) 用于 Bean 自身的初始化逻辑。
  • 销毁回调 (@PreDestroy 等) 用于 Bean 自身的清理逻辑。
  • 作用域 (scope) 影响生命周期:
    • singleton (默认):容器启动时创建(或第一次请求时,取决于配置),容器关闭时销毁。
    • prototype:每次请求时创建新实例。容器不管理原型 Bean 的销毁! 由获取它的代码负责释放资源(或依赖容器的销毁机制触发其 @PreDestroy,但需注意原型 Bean 通常不会触发容器级的销毁回调)。
    • request / session / application (Web 环境):生命周期分别绑定到 HTTP 请求、用户会话、ServletContext。
  • 理解顺序至关重要: 例如,依赖注入必须在 Aware 回调之前完成(因为 Aware 回调可能需要用到注入的属性),初始化回调必须在 BeanPostProcessor 的 postProcessBeforeInitialization 之后但在 postProcessAfterInitialization 之前执行。

掌握 Spring Bean 的生命周期对于理解 Spring 的运作原理、解决依赖注入问题、实现自定义扩展(如通过 BeanPostProcessor)以及正确管理资源(初始化/销毁)都至关重要。