上一篇我们分析了 IOC 容器的启动、包扫描以及 BeanDefinition 的注册流程。容器拿到“设计图纸”后,下一步就是按图索骥,开始生产 Bean 了。本篇将深入 Spring 的核心腹地,完整拆解一个 Bean 从无到有,再到销毁的整个生命周期源码。
一、Bean 生命周期总览
在深入代码之前,我们先从宏观上把握整个流程。当一个 BeanDefinition 已经注册到容器后,其生命周期主线如下:
BeanDefinition 已存在
↓
getBean(beanName)
↓
createBean() → 创建 Bean
↓
【1】实例化(newInstance / 构造器)
↓
【2】填充属性(依赖注入 @Autowired)
↓
【3】执行 Aware 接口
↓
【4】执行 BeanPostProcessor 前置
↓
【5】执行初始化方法(afterPropertiesSet / @PostConstruct)
↓
【6】执行 BeanPostProcessor 后置(AOP 在此植入)
↓
成品 Bean 放入单例池 singletonObjects
↓
容器关闭
↓
【7】执行销毁方法(destroy / @PreDestroy)
二、入口:一切从 getBean() 开始
我们通常这样从容器中获取一个 Bean:
UserService userService = context.getBean(UserService.class);
这行代码背后的源码调用链非常清晰。入口在 AbstractApplicationContext:
// AbstractApplicationContext
public <T> T getBean(Class<T> requiredType) {
return getBeanFactory().getBean(requiredType);
}
紧接着,请求被传递到 DefaultListableBeanFactory:
// DefaultListableBeanFactory
public <T> T getBean(Class<T> requiredType) throws BeansException {
return this.getBean(requiredType, (Object[])null);
}
public <T> T getBean(Class<T> requiredType, @Nullable Object... args) throws BeansException {
Assert.notNull(requiredType, "Required type must not be null");
Object resolved = this.resolveBean(ResolvableType.forRawClass(requiredType), args, false);
if (resolved == null) {
throw new NoSuchBeanDefinitionException(requiredType);
} else {
return resolved;
}
}
private <T> T resolveBean(ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) {
NamedBeanHolder<T> namedBean = this.resolveNamedBean(requiredType, args, nonUniqueAsNull);
// ........省略
}
private <T> NamedBeanHolder<T> resolveNamedBean(ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) throws BeansException {
// ........省略
if (candidateNames.length == 1) {
return this.resolveNamedBean(candidateNames[0], requiredType, args);
}//.........省略
}
private <T> NamedBeanHolder<T> resolveNamedBean(String beanName, ResolvableType requiredType, @Nullable Object[] args) throws BeansException {
Object bean = this.getBean(beanName, (Class)null, args);
return bean instanceof NullBean ? null : new NamedBeanHolder(beanName, this.adaptBeanInstance(beanName, bean, requiredType.toClass()));
}
最终,调用链会抵达 AbstractBeanFactory,这里是真正的起点:
// AbstractBeanFactory
public <T> T getBean(String name, @Nullable Class<T> requiredType, @Nullable Object... args) throws BeansException {
return this.doGetBean(name, requiredType, args, false);
}
其最基础的 getBean(String name) 方法也指向同一个核心方法:
// AbstractBeanFactory
public Object getBean(String name) {
return doGetBean(name, null, null, false);
}
三、核心:doGetBean 全流程
doGetBean 方法是整个获取逻辑的调度中心,它决定了是直接返回缓存对象,还是启动创建流程。
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType,
@Nullable Object[] args, boolean typeCheckOnly) {
// 1. 标准化 beanName(去掉 & 前缀)
String beanName = transformedBeanName(name);
// 2. 从一级缓存拿
Object sharedInstance = getSingleton(beanName);
// ==========================================
// 【你手动调用时,这里一定不为 null】
// 因为容器启动时已经创建好了
// ==========================================
if (sharedInstance != null && args == null) {
Object beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
// ... 省略父工厂、原型、自定义 scope ...
// ==========================================
// 【只有缓存为空,才会走到这里创建】
// 场景:
// 1. 容器内部第一次创建
// 2. @Lazy 第一次调用
// 3. prototype 每次调用
// ==========================================
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
// ↓↓↓ 真正创建 Bean ↓↓↓
return createBean(beanName, mbd, args);
} catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
});
Object beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// ... prototype 分支 ...
return adaptBeanInstance(name, beanInstance, requiredType);
}
可以看到,对于单例 Bean,创建逻辑被包装在一个 ObjectFactory(Lambda 表达式)中,传递给了 getSingleton 方法。这正是 Spring 解决循环依赖的关键设计之一。
四、createBean 真实入口
当需要创建 Bean 时,createBean 方法被调用,它主要做一些准备工作,真正的创建动作委托给了 doCreateBean。
// 类:AbstractAutowireCapableBeanFactory
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// ... 准备工作、class 加载、方法重写等 ...
// ↓↓↓ 核心:真正创建逻辑在 doCreateBean ↓↓↓
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
return beanInstance;
}
五、doCreateBean:生命周期的三个阶段
doCreateBean 方法是 Bean 生命周期的核心体现,它清晰地划分为三个阶段:
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// ====================== ① 实例化 Bean ======================
// 调用构造方法创建对象,生成 BeanWrapper
BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args);
Object bean = instanceWrapper.getWrappedInstance();
// ====================== ② 填充属性 ======================
// 依赖注入:@Autowired、@Resource 在这里处理
populateBean(beanName, mbd, instanceWrapper);
// ====================== ③ 初始化 Bean ======================
// Aware + BeanPostProcessor 前后置 + 初始化方法
Object exposedObject = initializeBean(beanName, bean, mbd);
return exposedObject;
}
六、initializeBean:初始化的精细步骤
第三阶段 initializeBean 内部又包含了我们熟知的经典步骤:
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
// 1. 执行各种 Aware 接口
invokeAwareMethods(beanName, bean);
// 2. BeanPostProcessor 前置处理
Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(bean, beanName);
// 3. 执行初始化方法
// @PostConstruct / afterPropertiesSet / init-method
invokeInitMethods(beanName, wrappedBean, mbd);
// 4. BeanPostProcessor 后置处理(AOP 代理在此生成)
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
return wrappedBean;
}
@Autowired 这类依赖注入发生在第二阶段 populateBean,而 @PostConstruct 和 InitializingBean.afterPropertiesSet 则发生在第三阶段的 invokeInitMethods 中。AOP 代理对象的生成是在第四步,由 BeanPostProcessor 后置处理器(AnnotationAwareAspectJAutoProxyCreator)完成的。
七、何时会触发 Bean 的创建?
并不是每次 getBean() 都会走创建流程。只有在以下情况,才会执行 createBean:
sharedInstance = getSingleton(beanName, () -> createBean(...));
- 容器内部第一次初始化:在
refresh() 方法的 finishBeanFactoryInitialization 阶段,通过 preInstantiateSingletons() 遍历创建所有非懒加载的单例 Bean。
- 懒加载 Bean 首次被请求:Bean 上标注了
@Lazy,只有在第一次主动 getBean() 时才创建。
- 原型作用域的 Bean:每次
getBean() 都会创建一个新的实例。
- Bean 被销毁后再次获取:这种情况较为罕见。
八、总结与回顾
让我们再梳理一下完整的脉络:
- 获取 BeanName → 从一级缓存
singletonObjects 尝试获取
↓
- 缓存不存在 → 进入单例创建逻辑
getSingleton
↓
- 执行
createBean → 进入真正创建入口
↓
doCreateBean 核心三阶段:
createBeanInstance:通过构造器实例化原生对象
populateBean:依赖注入,填充 @Autowired 属性
initializeBean:执行初始化逻辑
↓
initializeBean 内部精细步骤:
- 执行
Aware 接口(BeanNameAware/BeanFactoryAware)
- 执行
BeanPostProcessor 前置处理
- 执行初始化方法(
@PostConstruct / afterPropertiesSet)
- 执行
BeanPostProcessor 后置处理(生成 AOP 代理)
↓
- 创建完成,将成品 Bean 放入一级缓存
↓
- 后续任何
getBean 均直接从单例池返回
↓
- 容器关闭时,执行销毁方法(
@PreDestroy / destroy)
简单来说:
- Spring 容器启动时,默认会提前初始化(预实例化)所有单例 Bean。
- 你手动调用的
getBean(),大多数时候只是从一级缓存中获取现成的对象。
- 真正的 Bean 创建生命周期只发生在容器内部第一次实例化时。
- 完整的生命周期就是:实例化 → 属性填充 → Aware接口 → BeanPostProcessor前置 → 初始化方法 → BeanPostProcessor后置(AOP)→ 放入单例池。
理解这些核心步骤和源码位置,对于处理复杂的依赖注入问题、调试 Bean 创建顺序、或是编写自定义的 BeanPostProcessor 都至关重要。如果你想深入研究其他如 BeanDefinition 的解析或更底层的设计,可以查阅相关的技术文档进行系统学习。此外,在 云栈社区 的 Java 板块,也有很多开发者分享关于 Spring 核心机制的讨论和实践经验,可以作为延伸阅读。
下篇预告
在下一篇中,我们将挑战 Spring 面试中最经典、也是最难的问题之一:循环依赖与三级缓存的完整源码拆解。我们将弄清楚:
- 为什么 Spring 默认只能解决 setter 注入的循环依赖?
- 三级缓存每一级到底存放了什么对象?
- “早期引用”是如何解决循环依赖的?
- 构造器注入的循环依赖为何无法解决?