1. 前言
Spring是一个IOC(Inversion of Control,控制反转)
容器框架,拥有DI(Dependency Injection,依赖注入)
,DL(Dependency Lookup,依赖查找
等功能。
认为一个IOC框架最基本要有以下功能:
- 配置解析
- 对象创建
- 对象生命周期管理
本文基于Spring-5.2.2.RELEASE版本进行论述,为了简明扼要,在展示部分代码的时候省略了一些细节。
Spring Bean的生命周期总结因为没有一个正式的文档,因此是一个比较偏主观的分享,笔者只能结合小马哥的观点与自身的认识情况大概进行了总结,主要思路还是围绕着方法的调用栈,笔者认为,写在一个方法里,那么就可以认为是一个阶段。
2. Spring Bean生命周期
这里po一张我自己画的图:
我将SpringBean生命周期分为以下五个阶段:
- 注册阶段
- 合并阶段
- 实例化阶段
- 初始化阶段
- 销毁阶段
下面具体看一下每个阶段所做的事情。
2.1. 注册阶段
注册阶段的主要任务是通过各种BeanDefinitionReader读取各种配置来源信息(比如读取xml文件、注解等),并将其转化为BeanDefintion的过程。
这里要理解一下BeanDefinition的作用。众所周知,Spring提供了多种多样的注册Bean的方法,BeanDefinition的作用就是去定义并描述一个Spring Bean,方便后续解析实例化等操作。
ApplicationContext#register()
方法完成了对象注册阶段,其最终是调用的DefaultListableBeanFactory#registerBeanDefinition()
完成的BeanDefinition注册,这里的“注册”意思是将配置信息转化为BeanDefinition并放到合适的容器中,我们可以看以下代码:
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
/** Map of bean definition objects, keyed by bean name. */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
/** List of bean definition names, in registration order. */
private volatile List<String> beanDefinitionNames = new ArrayList<>(256);
//省略部分代码......
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
//省略了一些判断代码......
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
removeManualSingletonName(beanName);
}
}
其中,beanDefinitionMap的数据结构是ConcurrentHashMap
,因此不能保证顺序,为了记录注册的顺序,这里使用了ArrayList
类型的beanDefinitionNames用来记录注册顺序。
2.2. 合并阶段
经过了注册阶段,Spring的BeanDefinition容器中已经有了部分BeanDefinition信息(可能还存在通过aware接口或者postProcessor接口注册进来的beanDefinition),下面分为两种情况:
- 对于设置了非懒加载属性的BeanDefinition,在容器启动时(ApplicationContext#refresh())时会最终调用
BeanFactory#getBean()
方法进行实例化 - 对于懒加载(isLazyInit)的BeanDefinition,则需要在用到的时候调用
BeanFactory#getBean()
方法进行实例化。
事实上,无论哪种情况,Spring最终都会调用BeanFactory#getBean()
方法进行实例化。在getBean()方法中会有一个合并阶段:
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
//......
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
//......
}
}
AbstractBeanFactory#getMergedLocalBeanDefinition()
方法完成了BeanDefinition的合并,这里的“合并”的意思是,部分BeanDefinition可能不是RootBeanDefinition(没有parent),而是部分属性需要继承其他BeanDefinition,比如xml配置中的parent属性,这就需要进行一次合并,最终产出RootBeanDefinition。
RootBeanDefinition的parent设置时候会有一个判断,可以看出来,RootBeanDefinition最典型的特点就是没有parent reference:
public class RootBeanDefinition extends AbstractBeanDefinition {
//......
@Override
public void setParentName(@Nullable String parentName) {
if (parentName != null) {
throw new IllegalArgumentException("Root bean cannot be changed into a child bean with parent reference");
}
}
//......
}
2.3. 实例化阶段
到了实例化阶段,Spring将转化BeanDefinition中BeanDefinition为实例Bean(放在包装类BeanWrapper中)。
2.3.1. 通过ClassLoader赋值BeanDefinition的beanClass为Class对象
我们首先关注到AbstractAutowireCapableBeanFactory#createBean()
方法,AbstractAutowireCapableBeanFactory是DefaultListableBeanFactory的父类,在这个方法中有个过程:
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
implements AutowireCapableBeanFactory {
//......
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
if (logger.isTraceEnabled()) {
logger.trace("Creating instance of bean '" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd;
//......
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
//......
// Make sure bean class is actually resolved at this point, and
// clone the bean definition in case of a dynamically resolved Class
// which cannot be stored in the shared merged bean definition.
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass