Bean的生命周期:从Spring的子宫到坟墓

简介: Spring 管理 Bean 的生命周期,从对象注册、实例化、属性注入、初始化、使用到销毁,全程可控。Bean 的创建基于配置或注解,Spring 在容器启动时扫描并生成 BeanDefinition,按需实例化并填充依赖。通过 Aware 回调、初始化方法、AOP 代理等机制,实现灵活扩展。了解 Bean 生命周期有助于更好地掌握 Spring 框架运行机制,提升开发效率与系统可维护性。

上篇文章说到了我们创建对象的权利交给了 Spirng ,Spring 会将对象创建好并放入IOC 容器中。我们需要时,直接从 IOC 容器中获取即可。那么 Spring 是什么时候创建对象的呢

一、Bean的生命周期全景图

ddc3950555f9ae37c91be004a297d31b_MD5.jpeg

Bean 的定义与注册

尽管 Spring 接管了对象的创建,但是Spring 也是有原则的,他不会随随便便就创建 Bean。只有你在 Spring 中进行了注册,它才会接管这个对象的创建。

Spring 将自己管理的对象叫做Bean
向 Spring 注册Bean的方式一般有三种:

  • XML 配置
  • 注解(@Component@Service@Repository
  • 配置类

Spring 容器在启动时,会收集需要接管的Bean,把对 Bean 创建的要求打包在一个对象上,它把这个对象叫做BeanDefinition, 完成扫描并创建 BeanDefinition 的 工作的对象叫做BeanDefinitionReader ,收集完后,把所有的 BeanDefinition 放在了一个Map中,叫beanDefinitionMap

Spring 通过扫描 @Component@Service@Repository 等注解,或解析 XML/Java 配置,将类注册为 Bean。

  • 核心接口BeanDefinition(存储 Bean 的元数据,如作用域、是否懒加载等)
  • 注册方式

      // 注解方式
      @Component
      public class UserService {
          ... }
    
      // 配置类方式
      @Configuration
      public class AppConfig {
         
          @Bean
          public DataSource dataSource() {
          ... }
      }
    

    xml配置

      <bean id="myBean" class="com.example.MyBean"/>
    

此时Bean 尚未实例化,就像造冰箱时根据客户的要求画好了设计图,但是冰箱还没开始造。

状态

  • 未被实例化,仅以BeanDefinition形式存在于容器中。
  • 元数据已确定(如作用域、懒加载、初始化方法等)。

功能

  • 定义Bean的创建规则,相当于“蓝图”。
  • 支持通过BeanFactoryPostProcessor动态调整元数据。

三.Spring Bean的生命周期

Spring Bean的生命周期是从 Bean 实例化之后,即通过反射创建出对象之后,到Bean成为一个完整对象,最终被销毁。这个过程被称为Spring Bean的生命周期

1. Bean 的实例化

Spring 在创建Bean 前会遍历上面提到的beanDefinitionMap, 拿到BeanDefinition,通过反射来创建 Bean 的实例

  • 实例化时机
    • 单例 Bean:容器启动时(默认)或首次调用 getBean()(若配置懒加载)
    • 原型 Bean:每次 getBean() 调用时

此时的状态就像是按照设计图造好了冰箱的外壳,在仓库里已经占用了一块地方。可是里面的各项元件都是空的,根本无法使用。

  • 状态

    • 对象已通过反射创建(调用构造方法),但依赖未注入。
    • 此时Bean是“空壳”,字段为null或默认值。
  • 功能

    • 分配内存空间,完成对象基础构造。
    • 单例Bean在此阶段被缓存(若未配置懒加载)。

      2. 属性赋值

此时 Spring 为 Bean 设置相关属性和依赖,相关内容我们在上一篇的时候就跟大家讲过了

三种注入方式

  1. 构造器注入(推荐)

     @Service
     public class UserService {
         
         private final UserRepository userRepo;
         // 显式声明依赖
         public UserService(UserRepository userRepo) {
         
             this.userRepo = userRepo;
         }
     }
    
  2. Setter注入

     public class OrderService {
         
         private PaymentService paymentService;
    
         @Autowired
         public void setPaymentService(PaymentService paymentService) {
         
             this.paymentService = paymentService;
         }
     }
    
  3. 字段注入(不推荐)

     @Service
     public class ProductService {
         
         @Autowired
         private InventoryService inventoryService;
     }
    

技术要点

  • 构造器注入强制依赖完整性,适合必需依赖。
  • Setter注入适合可选依赖,支持动态更新。
  • 字段注入破坏封装性,难以测试,应谨慎使用。

此时的状态就是内部的元件也都装好了。作为一个冰箱已经可以正常的开始工作了

状态

  • 对象属性被填充(通过构造器、Setter或字段注入)。
  • Bean的依赖可能尚未完全初始化(循环依赖场景)。

功能

  • 解决对象间的依赖关系,确保Bean可用。
  • 若存在循环依赖,Spring通过三级缓存处理。

3. Bean 的初始化

初始化阶段执行自定义逻辑,顺序如下:

  1. Aware 接口回调
  2. BeanPostProcessor 前置处理
  3. @PostConstruct 注解方法
  4. InitializingBean.afterPropertiesSet()
  5. 自定义 init-method(XML 或 @Bean 配置)
@Component
public class OrderService {
   
    @PostConstruct
    public void init() {
    ... }  // 1. 最先执行

    @Override
    public void afterPropertiesSet() {
    ... }  // 2. 其次执行
}

AOP代理:

如果Bean被切面(AOP)拦截,它会被动态代理包装:

  • JDK动态代理(基于接口)
  • CGLIB代理(基于继承)

例子

@Transactional  
public void saveUser() {
     
    // 实际执行的是代理对象的增强逻辑  
}

状态

  • 依赖已注入完成,Bean处于“就绪”状态。
  • 可能已被AOP代理(代理对象替换原始对象)。

功能

  • 执行初始化逻辑(如资源加载、数据预热)。

4. Bean 的使用阶段

若 Bean 被 AOP 代理(如 @Transactional),实际调用的是代理对象的方法。

状态

  • Bean完全初始化,可被其他对象调用。
  • 若被AOP代理,实际调用的是代理对象。

功能

  • 执行业务逻辑,响应请求。
  • 单例Bean全局共享,原型Bean每次请求独立。

5. Bean 的销毁

容器关闭时,单例 Bean 会执行销毁逻辑,顺序如下:

  1. @PreDestroy 注解方法
  2. DisposableBean.destroy()
  3. 自定义 destroy-method(XML 或 @Bean 配置)
@Component
public class DatabasePool {
   
    @PreDestroy
    public void cleanup() {
    ... }  // 释放资源
}

状态

  • 单例Bean即将被容器回收,原型Bean不触发此阶段。
  • 对象仍存在,但即将被GC回收。

四、扩展点:干预生命周期

当你对Spring 建造的对象不满意时,Spring 提供了两种接口来让你手动干预 Bean 的创建,让你可以定制自己的 Bean

1. BeanPostProcessor

  • 干预时机:初始化前后。
  • 能力
    • 修改Bean实例(如包装为代理对象)。
    • @PostConstruct前插入逻辑。

示例

@Component
public class LoggingBeanPostProcessor implements BeanPostProcessor {
   
    @Override
    public Object postProcessBeforeInitialization(Object bean, String name) {
   
        System.out.println("初始化前:" + name);
        return bean;
    }
}

2. BeanFactoryPostProcessor

  • 干预时机:BeanDefinition注册后,实例化前。
  • 能力
    • 修改Bean的作用域、懒加载配置等。
    • 动态注册/移除BeanDefinition。

示例

@Component
public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
   
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory factory) {
   
        BeanDefinition definition = factory.getBeanDefinition("userService");
        definition.setScope(BeanDefinition.SCOPE_PROTOTYPE);
    }
}

五、总结:Bean 生命周期关键阶段

  1. 实例化(Instantiation):通过反射创建Bean对象(调用构造器);
  2. 属性注入(Populate):自动装配依赖的Bean(DI过程);
  3. 初始化(Initialization):执行自定义初始化逻辑(三种方式);
  4. 使用(Ready):Bean存入容器缓存,对外提供服务;
  5. 销毁(Destruction):Bean被容器回收,资源释放。

📌 注意事项

  1. 原型 Bean 的销毁需手动管理(Spring 不自动调用销毁方法)。
  2. 避免在初始化阶段阻塞(如远程调用),否则影响应用启动速度。
  3. 谨慎使用字段注入,推荐构造器注入以保证不可变性和可测试性。
相关文章
|
2月前
|
缓存 Java 开发者
【Spring】原理:Bean的作用域与生命周期
本文将围绕 Spring Bean 的作用域与生命周期展开深度剖析,系统梳理作用域的类型与应用场景、生命周期的关键阶段与扩展点,并结合实际案例揭示其底层实现原理,为开发者提供从理论到实践的完整指导。
|
SQL 关系型数据库 数据库
学习分布式事务Seata看这一篇就够了,建议收藏
学习分布式事务Seata看这一篇就够了,建议收藏
19462 2
|
3月前
|
缓存 Java Spring
Spring循环依赖:当两个Bean陷入鸡生蛋死循环时...
Spring中循环依赖问题常见于Bean相互依赖时,尤其在单例模式下。文章深入解析了循环依赖的成因及Spring的三级缓存解决方案,帮助理解Bean生命周期与依赖管理。
|
2月前
|
Java
Java的CAS机制深度解析
CAS(Compare-And-Swap)是并发编程中的原子操作,用于实现多线程环境下的无锁数据同步。它通过比较内存值与预期值,决定是否更新值,从而避免锁的使用。CAS广泛应用于Java的原子类和并发包中,如AtomicInteger和ConcurrentHashMap,提升了并发性能。尽管CAS具有高性能、无死锁等优点,但也存在ABA问题、循环开销大及仅支持单变量原子操作等缺点。合理使用CAS,结合实际场景选择同步机制,能有效提升程序性能。
|
2月前
|
人工智能 Java 开发者
【Spring】原理解析:Spring Boot 自动配置
Spring Boot通过“约定优于配置”的设计理念,自动检测项目依赖并根据这些依赖自动装配相应的Bean,从而解放开发者从繁琐的配置工作中解脱出来,专注于业务逻辑实现。
|
Java 开发者 Spring
Spring bean的生命周期详解!
本文详细介绍了Spring框架中的核心概念——Spring Bean的生命周期,包括实例化、属性赋值、接口回调、初始化、使用及销毁等10个阶段,并深入剖析了相关源码,如`BeanFactory`、`DefaultListableBeanFactory`和`BeanPostProcessor`等关键类与接口。通过理解这些核心组件,读者可以更好地掌握Spring Bean的管理和控制机制。
1282 1
|
2月前
|
存储 运维 关系型数据库
深入理解MySQL的MVCC(多版本并发控制)实现原理
总结起来,MVVC技术使得MySQL能够有效地支持高并发环境中复杂交互要求; 然而合理配置及运维管理仍然关键确保系统长期稳健运转.
237 16
|
8月前
|
Java
SpringBoot自动装配的原理
在SpringBoot项目的启动引导类上都有一个注解@SpringBootApplication 这个注解是一个复合注解, 其中有三个注解构成 , 分别是 ● @SpringBootConfiguration : 是@Configuration的派生注解 , 标注当前类是一个SpringBoot的配置类 ● @ComponentScan : 开启组件扫描, 默认扫描的是当前启动引导了所在包以及子包 ● @EnableAutoConfiguration : 开启自动配置(自动配置核心注解) 2.在@EnableAutoConfiguration注解的内容使用@Import注解导入了一个AutoC
|
缓存 Java 开发工具
Spring是如何解决循环依赖的?从底层源码入手,详细解读Spring框架的三级缓存
三级缓存是Spring框架里,一个经典的技术点,它很好地解决了循环依赖的问题,也是很多面试中会被问到的问题,本文从源码入手,详细剖析Spring三级缓存的来龙去脉。
1308 24
Spring是如何解决循环依赖的?从底层源码入手,详细解读Spring框架的三级缓存
|
12月前
|
Java 测试技术 开发者
Spring Boot 的优点详解
Spring Boot 的优点详解
1126 6