啃透Spring Bean生命周期:从源码层面堵上90%的Spring疑难杂症

你有没有遇到过@Value注入null、自定义初始化方法不执行、AOP代理不生效的问题?90%的Spring使用坑都和Bean生命周期有关,今天咱们从Spring 5.x核心源码出发,把Bean从生到死的全流程扒得明明白白,看完再也不会被同类问题卡脖子。
一、先搞懂:Bean生命周期到底是啥
很多开发者对Spring Bean生命周期的认知只停留在「实例化-初始化-销毁」的模糊概念上,其实每个阶段都有明确的执行顺序和扩展点,也是Spring高扩展性的核心支撑。
整个流程可以分为4大核心阶段:实例化、属性填充、初始化、销毁,接下来我们逐个拆解源码逻辑。
二、源码拆解:实例化阶段
实例化是Bean生命周期的第一个阶段,本质就是调用构造方法创建一个空的Bean对象,还没有填充任何属性。核心逻辑在AbstractAutowireCapableBeanFactory#createBeanInstance方法中:
// AbstractAutowireCapableBeanFactory#createBeanInstance核心逻辑
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// 1. 解析Bean对应的Class对象,校验是否可实例化
Class<?> beanClass = resolveBeanClass(mbd, beanName);
if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
}
// 2. 如果配置了FactoryMethod,就用工厂方法实例化
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// 3. 优先使用有参构造,没有的话用无参构造反射实例化
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}
// 4. 无参构造实例化,我们平时最常用的实例化方式
return instantiateBean(beanName, mbd);
}
重点注意:这个阶段生成的只是一个空的对象,所有属性都是默认值,@Autowired、@Value等注解还没有生效,不要在构造方法里依赖注入的属性,大概率会拿到null。
三、属性填充:依赖注入的核心逻辑
实例化完成之后就进入属性填充阶段,Spring会把Bean依赖的其他Bean、配置值等注入到对应的属性中,核心逻辑在AbstractAutowireCapableBeanFactory#populateBean方法:
// AbstractAutowireCapableBeanFactory#populateBean核心逻辑
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
// 遍历所有InstantiationAwareBeanPostProcessor,处理注解注入
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// 重点:AutowiredAnnotationBeanPostProcessor在这里处理@Autowired、@Value注入
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
pvs = pvsToUse;
}
}
// 把解析完成的属性值设置到Bean实例中
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
常见坑点:如果你的属性是static修饰的,Spring不会给静态属性注入值,因为Spring是给实例对象的属性注入,静态属性属于类本身,要注入的话可以通过set方法非静态化处理。
四、初始化阶段:功能增强的核心节点
属性填充完成之后进入初始化阶段,这是Spring扩展点最集中的阶段,AOP代理、自定义初始化逻辑都在这个阶段完成,核心逻辑在AbstractAutowireCapableBeanFactory#initializeBean方法:
// AbstractAutowireCapableBeanFactory#initializeBean核心逻辑
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
// 1. 执行Aware接口回调,把容器信息注入到Bean中
invokeAwareMethods(beanName, bean);
Object wrappedBean = bean;
// 2. 执行所有BeanPostProcessor的postProcessBeforeInitialization方法
// 比如CommonAnnotationBeanPostProcessor在这里处理@PostConstruct注解方法
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
// 3. 执行初始化方法:先执行InitializingBean的afterPropertiesSet,再执行自定义init-method
try {
invokeInitMethods(beanName, wrappedBean, mbd);
} catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
// 4. 执行所有BeanPostProcessor的postProcessAfterInitialization方法
// 重点:AOP动态代理就是在这里生成的,如果返回的是代理对象,后面使用的就是代理对象
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
return wrappedBean;
}
执行顺序牢记:Aware接口回调 → @PostConstruct方法 → InitializingBean.afterPropertiesSet → 自定义init-method方法 → AOP代理生成。如果你的初始化方法顺序不对,很大概率就是这里的顺序搞混了。
五、销毁阶段:资源释放的最后节点
当Spring容器关闭的时候,会触发Bean的销毁逻辑,主要是释放Bean占用的资源,比如数据库连接、文件流等,核心执行顺序是:先执行DisposableBean的destroy方法,再执行自定义的destroy-method方法。
需要注意的是,只有单例Bean会被Spring管理销毁逻辑,原型Bean Spring创建完成之后就不会再管理了,销毁逻辑需要开发者自己处理。
今天的源码拆解就到这啦,是不是感觉之前很多模模糊糊的Spring坑都有答案了?
夜雨聆风