>>>点击去看配套视频<<<
涉及Spring源码相关类和接口,代码浓度🌟🌟🌟🌟 理解大于记忆
从一个例子开始
小陈将开店规格单邮寄到咖啡加盟总部后,总部的设备管理中心按照规定的开店标准化流程,根据总部规范进行审计,然后进行选址装修、安装设备(安装完成后技术专家还会进行设备固件升级)、开业前检查等步骤后小陈可以正常营业了,工作人员还告知小陈后期如果关店的话,总部会进行设备的回收。
Bean的生命周期概念引入
上面说到的开店标准化流程,对应了Spring中的Bean的生命周期
-
填写开店规格单:小陈填写《开店规格单》(Bean元数据),总部解析并注册到设备管理中心(见Spring Bean元数据体系与Spring容器章节)
-
总部规范审计:设备中心专员收到申请后,先根据《设备白皮书》调整设备配置标准(如修改咖啡机型号参数),这对应BeanFactoryPostProcessor对元数据的预处理。
-
店面基础装修(实例化):施工队按调整后的标准进行场地硬装,相当于Spring创建Bean实例。
-
设备专家调试(前置处理):安装咖啡机后,技术专家进行固件升级(@PostConstruct前执行自定义逻辑),类似BeanPostProcessor前置处理
-
开业资质检查:调试完成后进行食品安全检测,对应Bean的初始化方法
-
设备性能优化(后置处理):正式营业前对咖啡机做压力测试(BeanPostProcessor后置处理)
-
正常营业(Bean就绪)
-
关店回收(@PreDestroy):总部按标准流程拆除回收设备
BeanFactoryPostProcessor是在容器加载Bean定义之后,实例化Bean之前执行的,用来修改Bean的定义。
而BeanPostProcessor则是在Bean实例化之后,初始化前后进行干预
理解BeanFactoryPostProcessor & BeanPostProcessor
3.1 BeanFactoryPostProcessor:设备管理中心的标准化审计流程
-
作用阶段:在容器加载Bean的定义(BeanDefinition)之后、但Bean实例化之前。
-
类比例子:小陈提交开店规格单后,总部设备管理中心的审计流程。
- 审计流程:总部根据规范审核小陈的规格单(如设备型号、装修方案等),可能会调整参数(如强制使用指定咖啡机型号)。
- 对应到Spring:BeanFactoryPostProcessor可以修改Bean的定义(例如将配置中的占位符替换为实际值,或强制某些属性值)。
-
关键点:
- 影响的是Bean的配置模板(未实例化)。
- 全局性操作,通常用于统一调整所有Bean的定义。
BeanFactoryPostProcessor是对整个设备管理中心的扩展性接口,可以调整BeanFactoryProcessor
@FunctionalInterface
public interface BeanFactoryPostProcessor {
// 调整整个beanFactory
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
3.2 BeanPostProcessor:设备的安装、升级和开业检查
-
作用阶段:在Bean实例化之后,分别在初始化方法(init)的前后介入。
-
类比例子:设备安装后的固件升级和开业前检查。
- 安装设备:实例化Bean(咖啡机、收银台等)。
- 固件升级(初始化前):技术专家在设备安装后、正式开业前升级固件(如调整咖啡机参数)。
- 开业检查(初始化后):确保设备正常运行(如测试咖啡机是否出杯正常)。
- 对应到Spring:BeanPostProcessor可以在初始化前后修改Bean实例(如注入代理、资源或执行校验)。
-
关键点:
- 影响的是已创建的Bean实例。
- 针对每个Bean单独处理,通常用于增强或监控Bean。
public interface BeanPostProcessor {
// 在bean初始化前处理
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
// 在bean初始化后处理
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
为什么要有Bean生命周期
Spring 的 Bean 生命周期机制是为了解决 对象管理复杂性 和 资源控制权分离 的核心问题。通过标准化的生命周期流程,Spring 实现了对 Bean 的 全流程托管,同时为开发者提供了灵活的 扩展点,使其既能享受框架的自动化管理,又能深度介入关键环节。
对象管理的复杂性
- 传统问题:在没有框架的情况下,开发者需要手动管理对象的创建、依赖注入、初始化和销毁。例如:
// 手动创建对象、依赖注入、初始化
UserService userService = new UserService();
userService.setUserDao(new UserDao());
userService.init();
// 使用后手动销毁
userService.destroy();
- Spring 的解决:将对象的创建、依赖注入、初始化和销毁交给容器统一管理,开发者只需声明 Bean 的配置。
资源控制权分离
- 传统问题:对象依赖的资源(如数据库连接、线程池)需要自行获取和释放,例如:
public class DataSource {
public void connect() { /* 获取连接 */ }
public void close() { /* 释放连接 */ }
}
- Spring 的解决:通过生命周期回调(如 @PostConstruct、@PreDestroy),将资源初始化和释放逻辑集中在 Bean 内部,与业务代码解耦。
Spring 生命周期&设计理念
Spring 生命周期设计理念主要有两部分:标准化的生命周期阶段 和 分层扩展点
标准化的生命周期阶段
- 围绕实例化的扩展点
Spring中的Bean也是Java中对象,因此Spring针对实例化前后设置了一系列扩展点
- 围绕初始化点扩展点
初始化是指bean实例化后,需要执行一些特定逻辑(比如连接池建立连接)的过程
Spring可以指定初始化方法,并在初始化前后进行扩展操作。
- 销毁
当spring容器关闭时回调单例bean的销毁方法
生命周期分层扩展点
4.2.1 闭环在bean本身的扩展点
spring中可以使用@PostConstruct定义在bean构造完成后回调方法,以及使用@PreDestroy定义在容器销毁前执行的方法,Spring容器会自动进行反射调用
有趣的是@PostConstruct和@PreDestroy并不是Spring定义的注解,而是Java EE 标准规范(JSR-250)定义的注解,通过支持标准注解,Spring 可以与其他遵循 Java EE 规范的框架(如 Jakarta EE)无缝集成,降低技术栈迁移成本。
例如:从传统 Java EE 应用迁移到 Spring Boot 时,原有代码中的 @PostConstruct 注解无需修改即可复用。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 定义 CoffeeShop Bean,指定初始化/销毁方法 -->
<bean id="coffeeShop" class="com.example.CoffeeShop"
init-method="openShop"
destroy-method="closeShop">
</bean>
</bean
AnnotatedGenericBeanDefinition beanDefinition = new AnnotatedGenericBeanDefinition(CoffeeShop.class);
beanDefinition.setInitMethodName("init");
beanDefinition.setDestroyMethodName("destroy");
如上展示了,如何通过xml和调用BeanDefinition接口方法的方式来指定初始化和销毁方法。即使是xml最终也还是记录到BeanDefinition实例中。Spring容器会在对应的实际进行反射调用
还有@Bean 注解的也可以指定初始化和销毁方法,后续讲解@Bean 注解的时候再详细介绍,这里不做过多展开
实现afterPropertiesSet方法,可以自定义初始化逻辑,当前Spring实例化bean并且完成属性注入后,会回调afterPropertiesSet(强转为InitializingBean类型,调用afterPropertiesSet方法,无需反射)
InitializingBean是Spring提供的标准化接口,毕竟目前很少使用xml来定义bean的初始化方法
实现destory方法,可以自定义销毁逻辑,当前Spring容器销毁时,会毁掉destory方法(强转为DisposableBean类型,调用destory方法,无需反射)
DisposableBean是Spring提供的标准化接口,毕竟目前很少使用xml来定义bean的销毁方法
实现afterSingletonsInstantiated方法,Spring容器初始化完所有单例bean方法后会统一的回调所有单例bean的afterSingletonsInstantiated方法
和InitializingBean不同,InitializingBean是每一个bean初始化完成后进行回调,无论是否单例,SmartInitializingSingleton是所有单例bean初始化完成后,轮流调用每一个单例bean的afterSingletonsInstantiated方法
Aware 意味感知,Spring提供实现Aware接口来感知容器的能力
在Spring框架中,Aware接口是一组用于让Bean感知容器特定功能的接口。它们允许Bean在初始化阶段获取Spring容器提供的底层资源或上下文信息,从而实现更灵活的交互。
小陈的咖啡店需要知道总部的联系方式,需要知道设备管理中心的联系方式,如何实现呢?
实现Aware类型接口,Spring会回调对应的方法
-
作用:注入ApplicationContext实例,使Bean能直接操作容器。
-
使用场景:动态获取其他Bean、访问环境变量、发布事件等。
-
示例:
public class CoffeeShop implements ApplicationContextAware {
// 总部联系方式写在墙上
private ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext context) {
this.context = context;
}
public void useContext() {
AnotherBean bean = context.getBean(AnotherBean.class);
}
}
-
作用:注入Bean在容器中的名称(ID或别名)。
-
使用场景:日志记录、根据Bean名称动态配置行为。
public class MyBean implements BeanNameAware {
private String beanName;
@Override
public void setBeanName(String name) {
this.beanName = name;
}
}
-
作用:注入BeanFactory实例,提供更底层的容器操作。
-
使用场景:检查Bean作用域、延迟初始化其他Bean。
-
示例:
public class MyBean implements BeanFactoryAware {
private BeanFactory factory;
@Override
public void setBeanFactory(BeanFactory factory) {
this.factory = factory;
}
public void checkScope() {
boolean isSingleton = factory.isSingleton("anotherBean");
}
}
-
作用:注入Environment对象,用于访问配置属性(如环境变量、配置文件)。
-
使用场景:读取外部化配置。
-
示例:
public class MyBean implements EnvironmentAware {
private Environment env;
@Override
public void setEnvironment(Environment env) {
this.env = env;
}
public String getProperty() {
return env.getProperty("my.config.key");
}
}
-
ResourceLoaderAware:获取ResourceLoader,用于加载类路径或文件系统资源。
-
MessageSourceAware:注入MessageSource,支持国际化消息处理。
-
ApplicationEventPublisherAware:发布应用事件。
-
调用阶段:在Bean的依赖注入(属性填充)之后,初始化回调(如@PostConstruct或InitializingBean)之前。
-
底层机制:Spring通过BeanPostProcessor(如ApplicationContextAwareProcessor)检测并处理Aware接口,BeanFactory在生成Bean后会判断是否实现了BeanFactoryAware回调对应方法
思考:为什么BeanFactory不识别ApplicationContextAware来回调对应方法呢?而是通过ApplicationContextAwareProcessor来回调?
4.2.2 针对所有bean的扩展点
除了如上闭环在bean本身的扩展点外,还有一种针对所有bean的扩展点,BeanPostProcessor bean的后置处理器
BeanPostProcessor 提供了多个扩展点,允许在Bean的生命周期中插入自定义逻辑。以下是主要扩展点及其作用:
定义Bean初始化前后的处理逻辑(例如总部在咖啡店开店前统一进行培训,开店后输出线上短视频引流)
-
postProcessBeforeInitialization 在Bean的初始化方法(如 @PostConstruct、InitializingBean.afterPropertiesSet())之前执行。
-
postProcessAfterInitialization(Object bean, String beanName) 在Bean的初始化方法之后执行,常用于生成代理对象(如AOP)。
public class CustomBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
System.out.println("初始化前处理:" + beanName);
//
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
System.out.println("初始化后处理:" + beanName);
return bean;
}
}
扩展BeanPostProcessor,干预Bean的实例化过程(比如实例化默认的咖啡豆供应商,关系户替换原供应商)
-
postProcessBeforeInstantiation(Class<?> beanClass, String beanName) 在Bean实例化前执行,可返回自定义对象替代原对象(如提前返回代理)。
-
postProcessAfterInstantiation(Object bean, String beanName) 在Bean实例化后、属性注入前执行。
-
postProcessProperties(PropertyValues pvs, Object bean, String beanName) 在属性注入时执行,用于处理 @Autowired注解进行属性注入。
public class CustomInstantiationProcessor implements InstantiationAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
if (beanClass == UserService.class) {
// 返回关系户
return
}
return null; // 默认实例化
}
}
处理Bean销毁前的逻辑:
- postProcessBeforeDestruction(Object bean, String beanName) 在Bean销毁前执行(如 @PreDestroy、DisposableBean.destroy() 方法前)。
public class CustomDestructionProcessor implements DestructionAwareBeanPostProcessor {
@Override
public void postProcessBeforeDestruction(Object bean, String beanName) {
if (bean instanceof DataSource) {
((DataSource) bean).close();
}
}
}
处理合并后的Bean定义(Spring中BeanDefinition具备继承体系,甚至可以进行方法充血):
- postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) 在Bean定义合并后、属性注入前执行,常用于缓存注解元数据(如 @Autowired 标记的字段)。
扩展InstantiationAwareBeanPostProcessor,解决循环依赖和构造函数选择问题
-
determineCandidateConstructors(Class<?> beanClass, String beanName) 确定Bean的构造函数,Spring会反射调用改构造函数进行对象实例化
-
getEarlyBeanReference(Object bean, String beanName) 在Bean未完全初始化时提前暴露引用(解决循环依赖)。
循环依赖会单独章节进行讲解
public class CustomSmartProcessor implements SmartInstantiationAwareBeanPostProcessor {
@Override
public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) {
// 选择带有特定注解的构造函数
return Arrays.stream(beanClass.getConstructors())
.filter(c -> c.isAnnotationPresent(Autowired.class))
.toArray(Constructor[]::new);
}
}
后续单独章节讲解源码,有所认识即可
4.2.3 容器级别的扩展点
在 Spring 框架中,BeanFactoryPostProcessor 允许在容器初始化后、Bean 实例化前修改 Bean 的定义(BeanDefinition)。以下是其核心扩展点及实现类:
作用:修改或覆盖 Bean 的定义(如属性值、作用域等)。
核心方法:void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
BeanDefinition beanDef = beanFactory.getBeanDefinition("userService");
beanDef.setInitMethod("init"); //设置初始化方法
}
}
在 BeanFactoryPostProcessor 的基础上,扩展了 动态注册新 Bean 的能力,核心方法
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
public class CustomRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
// 动态注册新 Bean
GenericBeanDefinition beanDef = new GenericBeanDefinition();
beanDef.setBeanClassName("com.example.UserService");
registry.registerBeanDefinition("userService", beanDef);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 修改现有 Bean 的定义
}
}
后续单独章节讲解源码,有所认识即可
面试题&知识总结
请详细描述Spring框架Bean的生命周期包括哪些阶段
理解大于记忆:
- 要意识到Spring中的bean也是对象:是对象就有实例化,因此Spring在实例化前后可以通过BeanPostProcessor进行扩展。实例化前可以返回对象,阻断BeanFactory创建对象;实例化后可以返回对象替换beanFactory创建的对象(例如:动态代理)
- 要意识到对象实例化了不代表可以使用:还需要进行初始化,因此Spring提供了众多的初始化扩展点,例如BeanPostProcessor在初始化前后可以进行扩展,还有可以通过BeanDefinition指定init-method、通过@PostContruct定义初始化方法,还可以实现InitializingBean来自定义初始化方法
- 要意识到bean还有销毁阶段:可以通过BeanDefinition指定destory-method、实验@PreDestory、实现DisposableBean
- 要理解生命周期扩展点是分层的:
- 闭环在bean本身的扩展点:🌰通过BeanDefinition指定init-method、通过@PostContruct定义初始化方法,还可以实现InitializingBean来自定义实例化方法(小陈可以自己定义自己的咖啡店要做哪些前置准备)
- 针对所有bean到扩展点:BeanPostProcessor(设备管理中心可以定义每一个咖啡店怎么处理,实例化前后,初始化前后等等)
- 针对容器的扩展点:BeanFactoryPostProcessor 可以对BeanDefinition,BeanFactory进行调整(总部可以对设备管理中心进行调整,可以为每一个咖啡店加上序号)
- 理解Aware:Aware接口是一组用于让Bean感知容器特定功能的接口。它们允许Bean在初始化阶段获取Spring容器提供的底层资源或上下文信息,从而实现更灵活的交互。
Spring生命周期,是Spring 管理的Bean从无到有的过程。
-
首先是BeanDefinition的生成,可以通过注解或者xml生成BeanDefinition,BeanDefinition指导Spring容器管理Bean。随后在Spring容器启动时可以通过BeanFactoryPostProcessor来对BeanFactory做扩展操作,甚至是改变BeanDefinition
-
Spring中的Bean也是一个个java对象,Spring会通过构造函数或者工厂方法反射生成bean,然后进行属性赋值依赖注入。这个过程可以通过BeanPostProccessor进行干预,在实例化前后进行扩展性操作。
-
初始化,Spring会调用Aware接口的方法,@PostConstruct 注解的方法,InitializingBean 接口的 afterPropertiesSet()、自定义 init-method(通过 XML 或 @Bean 指定)的方法,这个过程也可以通过BeanPostProcessor进行干预,在初始化前后进行扩展。
-
销毁:对于单例Bean会调用@PreDestroy 注解的方法、DisposableBean 接口的 destroy()。自定义 destroy-method(仅单例 Bean 生效)
-
痛点:代码重复、容易遗漏步骤(如忘记调用 destroy() 导致资源泄漏)。
-
痛点:资源获取和释放逻辑分散在业务代码中(使用完DataSource后需要手动调用close方法进行资源释放),难以维护。