目录
在学习Spring的过程中,我们都了解Spring是一个轻量化企业级的开发框架,通过IOC(依赖注入)和AOP(面向切面编程)为Java应用程序开发提供了全面的支持和解决方案。核心目标是简化企业级应用开发的复杂性,同时提升代码的可维护性、可扩展性和可测试性。Bean的生命周期是Spring框架的核心要点之一 ,也是一道经典的面试题!!!
Bean 的生命周期指的是 Spring 容器中 Bean 从实例化、初始化、使用到销毁的完整过程。理解其生命周期有助于更好地控制 Bean 的行为(如初始化资源、释放资源等),其设计源于 Spring 对对象管理的核心需求 ——通过 IOC 容器统一管控对象的创建与销毁,降低组件耦合,同时提供扩展点让开发者介入生命周期的关键阶段。接下来小编带大家了解生命周期的完整过程!!!🌹
Bean的生命周期概述
Spring Bean的生命周期主要包括以下几个阶段:
-
实例化(Instantiation):创建Bean的实例。
-
属性赋值(Populate):为Bean的属性设置值和引用。
-
初始化(Initialization):Bean的初始化过程,可以自定义初始化方法。
-
销毁(Destruction):当容器关闭时,Bean的销毁过程,也可以自定义销毁方法。
实例化
Bean 的实例化是 Spring 容器创建 Bean 对象的第一步,是整个生命周期的起点。
Bean实例化的核心要点
1. 触发时机
当 Spring 容器启动时,会根据配置(如 XML 配置、@Component
等注解、@Bean
方法等)扫描并解析出所有需要管理的 BeanDefinition
(Bean 的定义元数据)。当满足以下条件时,会触发 Bean 的实例化:
- 容器首次需要获取某个 Bean(如通过
getBean()
方法)。 - Bean 被其他已实例化的 Bean 依赖(依赖注入触发)。
- 非懒加载(
lazy-init="false"
)的单例 Bean,会在容器启动时提前实例化。
2. 实例化方式
Spring 支持多种 Bean 实例化方式:
(1)默认构造方法实例化
这是最常用的方式。Spring 会通过反射调用 Bean 类的无参构造方法来创建实例。要求 Bean 类必须包含无参构造方法,否则会抛出 BeanCreationException
。
public class UserService {
// 无参构造方法
public UserService() {
System.out.println("UserService 无参构造方法被调用");
}
}
配置(以 XML 为例):
<bean id="userService" class="com.example.UserService"/>
(2)带参构造方法实例化
若 Bean 类只有带参构造方法,或需要通过构造方法注入依赖,Spring 会根据配置的构造参数,调用对应的带参构造方法实例化 Bean。
public class OrderService {
private UserService userService;
// 带参构造方法
public OrderService(UserService userService) {
this.userService = userService;
System.out.println("OrderService 带参构造方法被调用");
}
}
配置(以 XML 为例):
<bean id="orderService" class="com.example.OrderService">
<constructor-arg ref="userService"/>
</bean>
(3)静态工厂方法实例化
通过调用静态工厂方法来创建 Bean 实例,工厂方法由开发者自定义,且必须是静态方法。
public class BeanFactory {
// 静态工厂方法
public static UserService createUserService() {
return new UserService();
}
}
配置(以 XML 为例):
<bean id="userService" class="com.example.BeanFactory" factory-method="createUserService"/>
(4)实例工厂方法实例化
先实例化工厂 Bean,再通过工厂 Bean 的实例方法来创建目标 Bean。
public class BeanFactory {
// 实例工厂方法
public UserService createUserService() {
return new UserService();
}
}
配置(以 XML 为例):
<!-- 先实例化工厂 Bean -->
<bean id="beanFactory" class="com.example.BeanFactory"/>
<!-- 通过工厂 Bean 的实例方法创建目标 Bean -->
<bean id="userService" factory-bean="beanFactory" factory-method="createUserService"/>
实例化只是创建了Bean的原始对象(只存储了对象的基本信息),此时对象仅完成创建,但尚未注入属性(依赖)、执行初始化逻辑。后续进入属性赋值和初始化阶段,最终成为可用的Bean
属性赋值
属性赋值(Populate)阶段承接实例化阶段,主要负责将 Bean 所依赖的其他 Bean 实例、配置参数等属性注入到已经实例化好的 Bean 中,使得 Bean 具备完整可用的状态。
1. 依赖注入
Spring 支持多种依赖注入方式,在属性赋值阶段会根据配置进行相应的依赖注入操作:
- 基于注解的依赖注入:常用的注解有
@Autowired
、@Qualifier
、@Resource
等。 - 基于 XML 的依赖注入:使用
<property>
标签进行属性注入,使用<constructor-arg>
标签进行构造函数注入。
2. 基本类型和集合类型属性赋值
除了注入其他 Bean,还可以对基本数据类型(如int
、String
等)、集合类型(如List
、Map
等)的属性进行赋值。
- 基本类型属性赋值:
- 基于注解:可以使用
@Value
注解为基本类型属性赋值。 - 基于 XML:通过
<property>
标签的value
属性赋值。
- 基于注解:可以使用
- 集合类型属性赋值:
- 基于注解:对于集合类型属性,可以直接注入符合类型要求的多个 Bean 实例。比如,注入多个
DataSource
的实现类到List
集合中。public class DataSourceManager { private List<DataSource> dataSourceList; @Autowired public DataSourceManager(List<DataSource> dataSourceList) { this.dataSourceList = dataSourceList; } }
- 基于 XML:使用
<list>
、<map>
等标签进行集合属性赋值。<bean id="dataSourceManager" class="com.example.DataSourceManager"> <property name="dataSourceList"> <list> <ref bean="dataSource1"/> <ref bean="dataSource2"/> </list> </property> </bean> <bean id="dataSource1" class="com.example.DataSource1"/> <bean id="dataSource2" class="com.example.DataSource2"/>
- 基于注解:对于集合类型属性,可以直接注入符合类型要求的多个 Bean 实例。比如,注入多个
3. 处理循环依赖
属性赋值阶段,Spring 容器会检测并处理循环依赖问题。对于单例 Bean,Spring 通过三级缓存机制来解决循环依赖。例如,A
依赖B
,B
又依赖A
,在属性赋值时,Spring 会先创建A
的早期暴露对象(未完全初始化)放入三级缓存,然后去实例化B
,B
在属性赋值时需要A
,就从缓存中获取A
的早期暴露对象完成注入,A
和B
都能顺利完成实例化和属性赋值 。不过,对于原型(prototype)Bean,Spring 不支持循环依赖处理,会抛出异常。
初始化
初始化阶段是在 Bean 实例化和属性赋值完成后,对 Bean 进行进一步 “完善” 的关键阶段,主要目的是让 Bean 从 “已创建但未就绪” 的状态,转变为 “可正常提供服务” 的状态。具体工作如下:
1. Aware 接口回调(可选)
Aware
接口是 Spring 提供的一组标记性接口,其核心作用是让 Bean 能够感知并获取 Spring 容器中的特定资源或上下文信息,从而与容器进行交互。
当 Spring 容器初始化 Bean 时,若发现 Bean 实现了某个 Aware
接口,会主动调用对应的回调方法,并将相关资源(如容器实例、Bean 名称等)传递给该 Bean。
我们用BeanNameAware接口举个例子
创建一个MyBean类实现BeanNameAware接口,回调(重写setBeanName方法)
import org.springframework.beans.factory.BeanNameAware;
public class MyBean implements BeanNameAware {
// 存储当前 Bean 在容器中的名称
private String beanName;
// 回调方法:Spring 容器会自动传入当前 Bean 的名称
@Override
public void setBeanName(String name) {
this.beanName = name;
System.out.println("当前 Bean 的名称是:" + name);
}
}
Spring配置
<bean id="myBean123" class="com.example.MyBean"/>
这里指定了 id="myBean123"
,因此 setBeanName
方法会收到 name="myBean123"
。
BeanNameAware
的唯一作用是:让 Bean 在初始化过程中,主动获取自己在 Spring 容器中的注册名称(即配置中的 id
或 name
属性值)。
2. Be
anPostProcessor
前置处理
容器中的所有 BeanPostProcessor
会执行 postProcessBeforeInitialization(Object bean, String beanName)
方法,对 Bean 进行初始化前的预处理(如修改 Bean 属性、生成代理对象等)。
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化前处理 Bean:" + beanName);
return bean; // 可返回修改后的 Bean,或原 Bean
}
}
3. InitializingBean
接口回调(可选)
若 Bean 实现了 InitializingBean
接口,容器会回调其 afterPropertiesSet()
方法,此时 Bean 的所有属性已注入完成,可执行初始化逻辑(如连接数据库、初始化缓存等)。
public class MyService implements InitializingBean {
private DataSource dataSource; // 假设已通过属性注入
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("执行 InitializingBean 的初始化逻辑");
// 例如:dataSource.getConnection() 测试连接
}
}
4. 自定义初始化方法(若配置)
若通过以下方式指定了自定义初始化方法,容器会调用该方法执行开发者定义的初始化逻辑:
- XML 配置:
<bean init-method="customInit"/>
- 注解:
@PostConstruct
(标注在方法上,JSR-250 规范) - Java 配置:
@Bean(initMethod = "customInit")
public class MyBean {
@PostConstruct
public void customInit() {
System.out.println("执行自定义初始化方法");
}
}
5. BeanPostProcessor
后置处理
容器中的所有 BeanPostProcessor
会执行 postProcessAfterInitialization(Object bean, String beanName)
方法,对 Bean 进行初始化后的再处理(如 AOP 代理增强,就是在此阶段生成代理对象)。
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化后处理 Bean:" + beanName);
return bean; // 可返回代理后的 Bean 等
}
}
初始化阶段是 Spring 为 Bean “赋能” 的核心环节:
- 通过
Aware
接口让 Bean 感知容器环境; - 通过
BeanPostProcessor
实现灵活的前后置处理; - 通过
InitializingBean
和自定义方法执行业务相关的初始化逻辑。
初始化完成后,Bean已具备完整的功能,成为可直接使用的成熟对象
- 对于单例 Bean:会被存入 Spring 容器的单例缓存池(
singletonObjects
),供应用程序多次获取和复用(每次获取的都是同一个实例)。 - 对于原型(双例) Bean:初始化完成后直接返回给调用者,容器不再管理其生命周期(后续使用、销毁均由开发者负责)。
销毁
1.注册 Destruction 相关回调接口
“注册 Destruction 相关回调接口” 是销毁阶段的准备工作,但它发生在 Bean 初始化完成后、进入 “使用中” 阶段之前,而非实际执行销毁逻辑的阶段。这一操作的本质是 “提前注册销毁时要执行的回调”,是销毁流程的前置准备
当 Spring 容器关闭(如应用停止)时,单例 Bean 正式进入销毁阶段(原型 Bean 不触发此流程),主要做以下工作:
2.DisposableBean
接口回调
若 Bean 实现了 DisposableBean
接口,容器会调用其 destroy()
方法,执行预定义的销毁逻辑(如关闭数据库连接、释放文件资源)。
public class MyBean implements DisposableBean {
@Override
public void destroy() throws Exception {
System.out.println("执行 DisposableBean 销毁逻辑");
}
}
3.自定义销毁方法执行
若通过 @PreDestroy
注解、XML 的 destroy-method
属性或 @Bean(destroyMethod)
指定了自定义销毁方法,容器会调用该方法。
public class MyBean {
@PreDestroy
public void customDestroy() {
System.out.println("执行自定义销毁方法");
}
}
通过一系列销毁操作后,容器会移除 Bean 从单例缓存池中的引用,最终 Bean 实例会被 JVM 垃圾回收机制回收。
Bean对象各个阶段的状态
小编在刚开始接触Bean生命周期时,认为实例化已经把完整对象造好了,但其实实例化只是 “造出对象壳子”,而真正的 “完整对象” 需要经过属性填充、初始化等一系列步骤后才形成。
为了让大家更能直观的感受到生命周期每个阶段Bean对象的状态,小编画了一个状态图
本次内容较为丰富,希望大家耐心观看 🌹
有问题欢迎留言!!!😗
肥嘟嘟左卫门就讲到这里啦,记得一键三连!!!😗