一.生命流程
要彻底搞清Spring的生命周期,首先要牢牢记住四个阶段。
- 实例化
- 属性赋值
- 初始化
- 销毁
源码如下,能证明实例化,属性赋值和初始化这三个生命周期的存在。本文中的Spring源码将会忽略无关部分,便于理解:
// 忽略了无关代码
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (instanceWrapper == null) {
// 实例化阶段!
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
// 属性赋值阶段!
populateBean(beanName, mbd, instanceWrapper);
// 初始化阶段!
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
}
对bean的生命周期的四个阶段展开更详细的描述:
- 实例化bean对象。
- 将配置文件中配置的属性填充到刚刚创建的bean对象中。
- 检查bean对象是否实现了Aware一类的接口,如果实现了则把相应的依赖设置到bean对象中。比如如果bean实现了BeanFactoryAware接口,Spring容器在实例化bean的过程中,会将BeanFactory容器注入到bean中。
- 调用BeanPostProcessor前置处理方法,即 postProcessBeforeInitialization(Object bean, String beanName)。
- 检查bean对象是否实现了InitializingBean接口,如果实现了,则调用afterPropertiesSet方法。或者检查配置文件中是否配置了init-method属性,如果配置了,则去调用init-method属性配置的方法。
- 调用 BeanPostProcessor 后置处理方法,即 postProcessAfterInitialization(Object bean, String beanName)。我们所熟知的 AOP 就是在这里将 Adivce 逻辑织入到 bean 中的。
- 注册Destruction相关回调方法。
- bean处于就绪状态,可以使用了。
- 应用上下文被销毁,调用注册Destruction相关方法。如果 bean 实现了 DispostbleBean 接口,Spring 容器会调用 destroy 方法。如果在配置文件中配置了 destroy 属性,Spring 容器则会调用 destroy 属性对应的方法。
二.详细细节和扩展点
2.1 设置属性
流程的第二步-设置属性,在这一步中,对于普通类型的属性,例如String,Integer等,比较容易处理,直接设置即可。但是如果某个bean对象依赖另一个bean对象,此时就不能直接设置了。Spring容器首先先要去实例化bean依赖的对象,实例化好了才能设置到当前bean中。
还有对循环依赖的处理,可以看:Spring IOC源码-循环依赖的解决方法
2.2 影响多个Bean的接口
实现了这些接口的Bean会切入到多个Bean的生命周期中。这些接口功能非常强大,Spring内部扩展也常用这些接口,例如自动注入以及AOP实现都与他们有关。
- BeanPostProcessor
- InstantiationAwareBeanPostProcessor
这两兄弟可能是Spring扩展中最重要的两个接口!InstantiationAwareBeanPostProcessor作用于实例化阶段的前后,BeanPostProcessor作用于初始化阶段的前后。正好和第一、第三个生命周期阶段对应。通过图能更好理解:
InstantiationAwareBeanPostProcessor实际上继承了BeanPostProcessor接口。InstantiationAwareBeanPostProcessor源码分析:
- postProcessBeforeInstantiation调用点,忽略无关代码:
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
// postProcessBeforeInstantiation方法调用点,在doCreateBean之前调用,也就是bean实例化之前调用
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
try {
// 上文提到的doCreateBean方法,可以看到
// postProcessBeforeInstantiation方法在创建Bean之前调用
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
}
- postProcessAfterInstantiation调用点,忽略无关代码:
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
// state of the bean before properties are set. This can be used, for example,
// to support styles of field injection.
boolean continueWithPropertyPopulation = true;
// InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation()
// 方法作为属性赋值的前置检查条件,在属性赋值之前执行,能够影响是否进行属性赋值!
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
continueWithPropertyPopulation = false;
break;
}
}
}
}
// 忽略后续的属性赋值操作代码
}
关于BeanPostProcessor执行阶段的源码穿插在下文Aware接口的调用时机分析中,因为部分Aware功能的就是通过他实现的!只需要先记住BeanPostProcessor在初始化前后调用就可以了
2.3 只调用一次的接口
2.3.1 接口分类
这一类接口的特点是功能丰富,常用于用户自定义扩展。这个有可以分为两类:
- Aware类型的接口,就是让我们可以拿到Spring中的一些资源。
- 生命周期接口
Aware接口的分组:
Aware Group1:
- BeanNameAware
- BeanClassLoaderAware
- BeanFactoryAware
Aware Group2:
- EnvironmentAware
- EmbeddedValueResolverAware 这个知道的人可能不多,实现该接口能够获取Spring EL解析器,用户的自定义注解需要支持spel表达式的时候可以使用,非常方便。
- ApplicationContextAware(ResourceLoaderAware\ApplicationEventPublisherAware\MessageSourceAware)
2.3.2 Aware调用时机源码分析
下面代码,忽略了部分无关代码。代码位置就是initializeBean方法,这也说明了Aware是在初始化阶段之前被调用。
// 见名知意,初始化阶段调用的方法
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
// 这里调用的是Group1中的三个Bean开头的Aware
invokeAwareMethods(beanName, bean);
Object wrappedBean = bean;
// 这里调用的是Group2中的几个Aware,
// 而实质上这里就是前面所说的BeanPostProcessor的调用点!
// 也就是说与Group1中的Aware不同,这里是通过BeanPostProcessor(ApplicationContextAwareProcessor)实现的。
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
invokeInitMethods(beanName, wrappedBean, mbd);
// BeanPostProcessor的另一个调用点
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
return wrappedBean;
}
可以看到并不是所有的Aware接口都使用同样的方式调用。Bean××Aware都是在代码中直接调用的,而ApplicationContext相关的Aware都是通过BeanPostProcessor#postProcessBeforeInitialization()实现的。
BeanPostProcessor的调用时机也能在这里体现,包围住invokeInitMethods方法,也就说明了在初始化阶段的前后执行。
2.3.3 两个简单生命周期接口
实例化和属性赋值都是Spring帮我们做的,能够自己实现的有初始化和销毁两个生命周期阶段。
- InitializingBean 对应生命周期的初始化阶段,在上面源码的
invokeInitMethods(beanName, wrappedBean, mbd);
方法中调用。
有一点需要注意,因为Aware方法都是执行在初始化方法之前,所以可以在初始化方法中放心大胆的使用Aware接口获取的资源,这也是我们自定义扩展Spring的常用方式。
除了实现InitializingBean接口之外还能通过注解或者xml配置的方式指定初始化方法,至于这几种定义方式的调用顺序其实没有必要记。因为这几个方法对应的都是同一个生命周期,只是实现方式不同,我们一般只采用其中一种方式。 - DisposableBean 类似于InitializingBean,对应生命周期的销毁阶段,以ConfigurableApplicationContext#close()方法作为入口,实现是通过循环取所有实现了DisposableBean接口的Bean然后调用其destroy()方法 。感兴趣的可以自行跟一下源码。