Spring Bean 生命周期详解

Spring Bean 生命周期详解

Spring Bean 的生命周期是 Spring IoC 容器管理 Bean 对象从创建到销毁的整个过程。理解 Bean 的生命周期对于深入掌握 Spring 框架至关重要。下面将详细介绍 Spring Bean 的完整生命周期。

一、Bean 生命周期概览

Spring Bean 的生命周期可以分为以下主要阶段:

  1. 实例化(Instantiation)
  2. 属性赋值(Populate Properties)
  3. 初始化(Initialization)
  4. 使用(In Use)
  5. 销毁(Destruction)

二、详细生命周期阶段

1. 实例化(Instantiation)

实例化是创建 Bean 对象的第一步,Spring 容器通过反射机制创建 Bean 的实例。

  • 对于 XML 配置,Spring 从 <bean> 标签中读取 class 属性
  • 对于注解配置,Spring 通过 @Component 等注解找到对应的类
  • 使用构造函数创建 Bean 实例

2. 属性赋值(Populate Properties)

在实例化后,Spring 容器将为 Bean 注入配置的属性值和依赖的其他 Bean。

  • XML 配置中的 <property><constructor-arg> 标签
  • 注解配置中的 @Autowired@Resource 等注解
  • setter 方法注入或构造函数注入

3. 初始化(Initialization)

初始化阶段是 Bean 准备就绪前的最后一步,包含多个回调方法的执行。按照执行顺序:

3.1 Aware 接口回调

Spring 提供了一系列的 Aware 接口,用于让 Bean 获取 Spring 容器的特定资源:

  • BeanNameAware :通过 setBeanName(String name) 方法获取 Bean 在容器中的名称
  • BeanClassLoaderAware :通过 setBeanClassLoader(ClassLoader classLoader) 方法获取加载 Bean 的类加载器
  • BeanFactoryAware :通过 setBeanFactory(BeanFactory beanFactory) 方法获取 BeanFactory 容器实例
  • ApplicationContextAware :通过 setApplicationContext(ApplicationContext applicationContext) 方法获取 ApplicationContext 容器实例
3.2 BeanPostProcessor 前置处理

BeanPostProcessor 接口的 postProcessBeforeInitialization(Object bean, String beanName) 方法在初始化前被调用,可以对 Bean 进行加工处理。

3.3 初始化回调
  • InitializingBean 接口 :实现该接口的 Bean 会调用 afterPropertiesSet() 方法
  • 自定义 init-method :通过 XML 的 init-method 属性或 @Bean 注解的 initMethod 属性指定的初始化方法
3.4 BeanPostProcessor 后置处理

BeanPostProcessor 接口的 postProcessAfterInitialization(Object bean, String beanName) 方法在初始化后被调用,可以对初始化完成的 Bean 进行最后的加工处理。

4. 使用(In Use)

初始化完成后,Bean 就可以被应用程序使用了。

  • 单例(Singleton)Bean:容器启动时就完成实例化和初始化,一直存在直到容器关闭
  • 原型(Prototype)Bean:每次请求时创建新实例,使用完后由客户端负责销毁

5. 销毁(Destruction)

当容器关闭时,对于单例 Bean,会执行销毁操作:

  • DisposableBean 接口 :实现该接口的 Bean 会调用 destroy() 方法
  • 自定义 destroy-method :通过 XML 的 destroy-method 属性或 @Bean 注解的 destroyMethod 属性指定的销毁方法

三、生命周期流程图

scss 复制代码
实例化 (创建Bean对象) 
    ↓
属性赋值 (注入依赖) 
    ↓
Aware接口回调
    ↓
BeanPostProcessor.postProcessBeforeInitialization()
    ↓
InitializingBean.afterPropertiesSet()
    ↓
自定义init-method
    ↓
BeanPostProcessor.postProcessAfterInitialization()
    ↓
Bean就绪,可以使用
    ↓
容器关闭
    ↓
DisposableBean.destroy()
    ↓
自定义destroy-method

四、Bean 生命周期与作用域的关系

不同作用域的 Bean 在生命周期上有显著差异:

单例(Singleton)Bean

  • 容器启动时创建(除非配置了懒加载)
  • 容器关闭时销毁
  • 整个应用程序共享同一个实例

原型(Prototype)Bean

  • 每次请求时创建
  • Spring 容器只负责创建,不负责销毁
  • 销毁由客户端代码负责

Web 相关作用域

  • request:每个 HTTP 请求创建一个实例,请求结束时销毁
  • session:每个 HTTP 会话创建一个实例,会话结束时销毁
  • application:整个 Web 应用创建一个实例,应用关闭时销毁

五、实际应用示例

下面通过代码示例来说明如何使用 Bean 生命周期回调:

示例1:实现生命周期接口

java 复制代码
public class LifecycleBean implements 
        BeanNameAware, 
        BeanFactoryAware, 
        InitializingBean, 
        DisposableBean {
    
    private String beanName;
    private BeanFactory beanFactory;
    
    @Override
    public void setBeanName(String name) {
        this.beanName = name;
        System.out.println("BeanNameAware: 设置Bean名称为 " + name);
    }
    
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
        System.out.println("BeanFactoryAware: 设置BeanFactory");
    }
    
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean: 属性设置完成后执行初始化");
    }
    
    // 自定义初始化方法
    public void customInit() {
        System.out.println("自定义初始化方法: customInit");
    }
    
    @Override
    public void destroy() throws Exception {
        System.out.println("DisposableBean: 执行销毁操作");
    }
    
    // 自定义销毁方法
    public void customDestroy() {
        System.out.println("自定义销毁方法: customDestroy");
    }
}

示例2:使用 BeanPostProcessor

java 复制代码
public class CustomBeanPostProcessor implements BeanPostProcessor {
    
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("BeanPostProcessor前置处理: " + beanName);
        // 可以对bean进行修改或替换
        return bean;
    }
    
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("BeanPostProcessor后置处理: " + beanName);
        // 可以对bean进行修改或替换
        return bean;
    }
}

示例3:XML 配置生命周期方法

xml 复制代码
<bean id="lifecycleBean" 
      class="com.example.LifecycleBean" 
      init-method="customInit" 
      destroy-method="customDestroy"/>

<bean class="com.example.CustomBeanPostProcessor"/>

示例4:Java 配置生命周期方法

java 复制代码
@Configuration
public class AppConfig {
    
    @Bean(initMethod = "customInit", destroyMethod = "customDestroy")
    public LifecycleBean lifecycleBean() {
        return new LifecycleBean();
    }
    
    @Bean
    public CustomBeanPostProcessor customBeanPostProcessor() {
        return new CustomBeanPostProcessor();
    }
}

六、在本项目中的体现

虽然当前项目没有直接实现所有生命周期接口,但项目中的配置和测试仍然体现了 Bean 生命周期的核心概念:

  1. Bean 定义与实例化:通过 XML 和 Java 配置定义 Bean

  2. 属性赋值:如 applicationContext.xml中的构造函数注入:

    xml 复制代码
    <constructor-arg name="id" value="200"/>
    <constructor-arg name="username" value="xml-admin"/>
  3. Bean 作用域:在config/BeanFactoryConfig.java 中定义了单例和原型 Bean

  4. 作用域测试:在 BeanFactoryTest.java 中测试了单例和原型作用域

七、最佳实践

  1. 优先使用接口回调 :实现 InitializingBeanDisposableBean 接口比自定义 init/destroy 方法更直接

  2. 使用 JSR-250 注解 :Spring 支持标准的 @PostConstruct@PreDestroy 注解,它们不耦合于 Spring 框架

  3. 谨慎使用 BeanPostProcessor:它会影响所有 Bean,确保处理逻辑高效且正确

  4. 注意原型 Bean 的销毁:Spring 容器不负责销毁原型 Bean,需要客户端代码管理

  5. 避免在初始化方法中做耗时操作:这会延长容器启动时间

八、总结

Spring Bean 的生命周期是一个精心设计的流程,通过一系列的回调方法,允许开发者在 Bean 的不同阶段执行自定义逻辑。掌握 Bean 的生命周期对于开发健壮的 Spring 应用程序非常重要,可以帮助开发者更好地控制 Bean 的创建、配置和销毁过程,从而实现更灵活和强大的功能。

相关推荐
极光代码工作室11 分钟前
基于SpringBoot的流浪狗管理系统的设计与实现
java·spring boot·后端
Rust语言中文社区18 分钟前
【Rust日报】Dioxus 用起来有趣吗?
开发语言·后端·rust
小灰灰搞电子21 分钟前
Rust Slint实现颜色选择器源码分享
开发语言·后端·rust
boolean的主人35 分钟前
mac电脑安装nginx+php
后端
boolean的主人38 分钟前
mac电脑安装运行多个php版本
后端
oouy1 小时前
Java的三大特性:从懵圈到通透的实战指南
后端
狂炫冰美式2 小时前
3天,1人,从0到付费产品:AI时代个人开发者的生存指南
前端·人工智能·后端
Java水解2 小时前
PostgreSQL 自增序列SERIAL:从原理到实战
后端·postgresql
悟空码字3 小时前
单点登录:一次登录,全网通行
java·后端
倚肆3 小时前
Spring Boot Security 全面详解与实战指南
java·spring boot·后端