说说Bean的生命周期

Spring Bean 的生命周期是 Spring 框架的核心机制之一,指 Bean 从创建到销毁的完整过程,包含多个阶段和扩展点。以下是其核心流程及关键环节的详解:

一、Bean 生命周期的核心阶段

  1. 实例化(Instantiation)

    • 作用:根据 Bean 定义(XML、注解或配置类),通过反射或工厂方法创建对象。

    • 关键点:

      • 调用构造函数(无参或指定构造器)生成对象。

      • 若存在 InstantiationAwareBeanPostProcessor,可在实例化前后干预(如修改 Bean 定义或返回代理对象)。

  2. 属性赋值(Population)

    • 作用:为 Bean 注入依赖和配置值。

    • 实现方式:

      • Setter 注入:通过反射调用 Setter 方法。

      • 构造器注入:实例化时通过构造参数注入。

      • 注解注入:@Autowired、@Value等自动注入属性和配置。

    • 循环依赖解决:

      • Spring 通过三级缓存(singletonFactories、earlySingletonObjects、singletonObjects

        )解决循环引用问题。

        • 一级缓存:存储完整 Bean(初始化完成)。

        • 二级缓存:存储半成品 Bean(已实例化但未初始化)。

        • 三级缓存:存储 Bean 工厂,用于提前暴露引用。

  3. 初始化(Initialization) 此阶段通过多个扩展点按顺序执行初始化逻辑:

    扩展点 执行顺序 作用
    Aware 接口回调 1 注入容器资源(如 BeanNameAware 获取 Bean 名称,ApplicationContextAware 获取上下文)
    @PostConstruct 2 注解标记的方法,在依赖注入后执行
    InitializingBean#afterPropertiesSet() 3 接口方法,属性赋值完成后调用
    自定义 init-method 4 XML 或 @Bean(initMethod="...") 指定的方法
    BeanPostProcessor#postProcessAfterInitialization() 5 初始化后执行(如生成 AOP 代理对象)
  4. 销毁(Destruction)

    • 触发时机:容器关闭时(如 context.close())。

    • 执行顺序:

      1. @PreDestroy注解方法

      2. DisposableBean#destroy()接口方法

      3. 自定义destroy-method(XML 或@Bean配置)


二、特殊场景与注意事项

  1. 作用域对生命周期的影响

    • 单例 Bean(Singleton):生命周期由容器管理,初始化后存入单例池,容器关闭时销毁。

    • 原型 Bean(Prototype):容器不管理销毁,需手动调用ConfigurableBeanFactory.destroyBean()释放资源。

    • Web 作用域(Request/Session):由子容器(如RequestContextListener)管理销毁。

  2. 循环依赖的限制

    • 构造器注入:无法通过三级缓存解决循环依赖,需改用 Setter 或字段注入。

    • 解决方案:避免循环依赖或使用@Lazy延迟加载。

  3. 性能优化建议

    • 避免在初始化阶段执行耗时操作(如远程调用),可结合@Lazy延迟加载。

    • 利用BeanPostProcessor统一处理日志、监控等横切关注点,减少重复代码。

三、理解生命周期的意义

  • 解耦与扩展:通过生命周期回调(如InitializingBean、BeanPostProcessor)将业务逻辑与框架管理分离,支持灵活扩展。

  • 资源管理:在初始化和销毁阶段处理资源加载(如数据库连接)和释放(如关闭连接),避免内存泄漏。

  • 框架整合:生命周期机制为 AOP、事务管理等高级功能提供基础(如 AOP 代理在初始化后阶段生成)。

流程图总结实例化 → 属性注入 → Aware回调 → @PostConstruct → afterPropertiesSet → init-method → BeanPostProcessor后置处理 → 使用阶段 → @PreDestroy → destroy() → destroy-method

掌握 Bean 的生命周期,能更高效地利用 Spring 的扩展能力,优化应用性能与稳定性。实际开发中,建议结合日志观察各阶段输出(如示例中的 OrderService),加深理解。

四、代码案例展示

4.1 实例化(Instantiation)

作用:通过反射或工厂方法创建 Bean 实例。 ​​代码示例​​:

public class OrderService {
    public OrderService() {
        System.out.println("1. 实例化:调用构造方法");
    }
}

关键点

  • 若使用@Bean注解配置,Spring 调用其方法创建实例。

  • 若配置 XML,则通过触发构造方法。

4.2 属性赋值(Populate Properties)

作用:注入依赖项和配置值(如 @Autowired@Value)。 ​​代码示例​​:

public class OrderService {
    private UserService userService;
​
    // Setter 注入
    @Autowired
    public void setUserService(UserService userService) {
        this.userService = userService;
        System.out.println("2. 属性赋值:依赖注入完成");
    }
}
  • 关键点:

    • Spring 通过反射调用 Setter 方法或构造器注入属性。

    • 循环依赖通过三级缓存解决(单例模式下)。

初始化(Initialization)

作用:执行自定义初始化逻辑,包含多个扩展点(按顺序执行):

1. Aware 接口回调
public class OrderService implements BeanNameAware {
    @Override
    public void setBeanName(String name) {
        System.out.println("3.1 Aware 回调:注入 Bean 名称 - " + name);
    }
}
2. 初始化方法执行顺序
扩展点 执行顺序 代码示例
@PostConstruct 最先执行 @PostConstruct public void init() { System.out.println("3.2 @PostConstruct"); }
InitializingBean 其次执行 public void afterPropertiesSet() { System.out.println("3.3 InitializingBean"); }
自定义 init-method 最后执行 @Bean(initMethod = "customInit") 或 XML 中配置 `init-method
3. BeanPostProcessor 拦截
public class MyProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessAfterInitialization(Object bean, String name) {
        if (bean instanceof OrderService) {
            System.out.println("3.4 生成 AOP 代理(后置处理)");
        }
        return bean;
    }
}
  • 关键点:

    • AOP 代理在此阶段生成(postProcessAfterInitialization)。

    • 初始化顺序不可变:@PostConstruct→InitializingBean→init-method。

使用阶段(In Use)

作用:Bean 已就绪,可被其他组件调用。 ​​代码示例​​:

public class App {
    public static void main(String[] args) {
        ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
        OrderService service = ctx.getBean(OrderService.class);
        service.createOrder(); // 4. 业务方法调用
    }
}

销毁(Destruction)

作用:容器关闭时释放资源(如数据库连接)。 ​​销毁方法执行顺序​​:

扩展点 执行顺序 代码示例
@PreDestroy 最先执行 @PreDestroy public void preDestroy() { System.out.println("5.1 @PreDestroy"); }
DisposableBean 其次执行 public void destroy() { System.out.println("5.2 DisposableBean"); }
自定义 destroy-method 最后执行 @Bean(destroyMethod = "cleanup") 或 XML 中配置 `destroy-method

触发条件:ctx.close(); // 关闭容器触发销毁

  • 关键点:

    • 原型 Bean 的销毁需手动调用 ctx.getBeanFactory().destroyBean(bean)。

    • 单例 Bean 由容器自动管理销毁。

完整生命周期流程图

说说Bean的生命周期_第1张图片

实例化属性赋值Aware 回调BeanPostProcessor 前置处理初始化方法BeanPostProcessor 后置处理使用阶段销毁

⚠️ 注意事项

  1. 作用域影响:

    • 单例 Bean 的初始化在容器启动时完成,原型 Bean 在每次获取时初始化。

  2. 循环依赖:

    • 构造器注入无法解决循环依赖,需改用 Setter/字段注入。

  3. 性能优化:

    • 避免在初始化阶段执行耗时操作(如远程调用),可使用@Lazy延迟加载。

源码入口: 生命周期核心逻辑位于 AbstractAutowireCapableBeanFactorydoCreateBean() 方法

。掌握这些阶段与扩展点,能更灵活地控制 Bean 的行为,提升资源管理效率与代码可维护性。

你可能感兴趣的:(springboot,java,spring,开发语言)