Spring Bean 生命周期简单分析
容器是 Spring 设计中一个核心组件,它负责管理 Bean 实例,并提供了接口 BeanFactory
使用。
网上对这个有太多分析的文章了,但大多繁琐不堪,不易新手理解,这里就只对关键步骤做个简单分析。
文章中所研究的 Spring 版本为 5.1.4
创建
Bean 的创建是其生命周期中最复杂的一步,这边对 getBean
方法跟踪,进入到了 AbstractBeanFactory
的 doGetBean
方法,该方法的内容就是构造 Bean 的主要流程,这里只将关键的步骤提取出来。
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
final String beanName = transformedBeanName(name); // 解析 Bean 名称
Object bean;
Object sharedInstance = getSingleton(beanName); // 1. 获取 Bean 实例或构造工厂
if (sharedInstance != null && args == null) {
// 这里主要是对构造工厂进行创建实例
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
} else {
BeanFactory parentBeanFactory = getParentBeanFactory();
// 检查父级构造工厂是否包含实例,是则交由父级工厂创建返回
...
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// 初始化当前 Bean 所依赖的 Bean
...
// 2. 根据 Bean 的类型选择构造方式,这里分析单例模式
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args); // 具体构造实例的逻辑
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// 类型检查和转换
...
return (T) bean;
}
获取单例
其实整个流程十分复杂,这里也能够看出 Spring 的严谨性。首先跟进 1. getSingleton()
,它的逻辑虽然简单,但其实是对解决循环依赖问题非常关键的一步。
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
这里有两个解决循环引用的要点,这里先知道就行。
-
一是
isSingletonCurrentlyInCreation(beanName)
,这是标记了一个 Bean 正处于构造阶段中。 -
还有一个是
this.singletonFactories.get(beanName)
,这里返回的是 Bean 实例的构造工厂,需要在其他位置通过调用addSingletonFactory
加入进来。
创建 Bean 实例
创建实例调用的内容非常多,这边主要讲下构造、注入、处理器的过程。
首先看到 2. getSingleton()
,这里需要关注的只有这几步,
-
beforeSingletonCreation
和afterSingletonCreation
分别为标记 Bean 在创建中和移除标记 -
使用前面的
createBean
创建实例。 -
addSingleton
则是将创建的实例加入到容器中。
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
beforeSingletonCreation(beanName);
try {
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
finally {
afterSingletonCreation(beanName);
}
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
return singletonObject;
}
继续分析 createBean
,其实里面主要是委托了 doCreateBean
方法来创建实例,解决循环引用的关键点就是这里的 addSingletonFactory
,使得 Bean 在创建阶段就提供依赖引用。
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// 创建实例,会涉及构造器注入
BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args);
final Object bean = instanceWrapper.getWrappedInstance();
// 缓存实例引用
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
Object exposedObject = bean;
// 初始化实例
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
return exposedObject;
}
初始化
当 Bean 在 doCreateBean
中完成了实例的创建,接着就会对实例进行属性注入
、调用初始化方法
、执行前置/后置处理器
,而后将实例加入到 Spring 容器中,就完成了一个 Bean 的创建阶段。
这个过程也可以通过
AutowireCapableBeanFactory#initializeBean
来完成。
销毁
一个 Bean 实例的销毁可以随着 Spring 生命周期结束而触发,也可以通过调用 AutowireCapableBeanFactory
中的 destroyBean
来进行。
他将构造一个 DisposableBeanAdapter
来执行不同实例的销毁流程,这里的代码流程清晰明了。
public void destroy() {
for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) {
processor.postProcessBeforeDestruction(this.bean, this.beanName); // 执行前置销毁处理器
}
// 执行实现 DisposableBean 的销毁方法
((DisposableBean) this.bean).destroy();
// 执行自定义销毁方法
invokeCustomDestroyMethod(this.destroyMethod);
}
时序图
用时序图展示 创建初始化
的流程以便更好的理解。