Spring Bean的生命周期真的是面试的时候对于Spring的最高频的考点之一了,笔者已经被这个问题问懵了不止一次,始终记不住那一大串的步骤,但实际上尝试去死记硬背那些步骤的我是谬误的,外表上看只是背诵一个流程,实际上,这个流程牵扯到的知识点可是很多而且很有意思的。
上面这个图我想很多人应该都看过雷同的或者类似的:
看起来还是挺长的对吧,然而咱们其实能够把它划分成上面四个大的步骤:
- 实例化Bean
- 设置对象属性,依赖注入
- 初始化
- destroy:bean的销毁
接下来,我会依据这个步骤,一步步的解说相干的知识点,从生命周期登程,将Spring中重要的类或接口来一一阐明。
一、实例化Bean
这第一步,容器通过获取BeanDefinition对象中的信息进行实例化。并且这一步仅仅是简略的实例化,并未进行依赖注入,能够了解成new xx()。但要留神的是,对于BeanFactory容器和ApplicationContext容器它们的实例化是有区别的。
- 对于BeanFactory容器,当客户向容器申请一个尚未初始化的bean时,或初始化bean的时候须要注入另一个尚未初始化的依赖时,容器就会调用createBean()进行实例化。
- 对于ApplicationContext容器,当容器启动完结后,便实例化所有的bean。
那么既然提到了BeanFactory和ApplicationContext,我就对这两个接口也简略介绍一下。它们别离位于org.springframework.beans和org.springframework.context两个包下,而这两个包,正是Spring IoC容器的根底。BeanFactory提供了框架最根底的一些性能,包含IOC的配置机制,提供Bean的各种定义,建设Bean之间的依赖关系等。ApplicationContext继承了BeanFactory,因而它领有BeanFactory的所有性能,但它自身还继承了一些其余的接口,比方音讯资源配置,事件公布等。
BeanFactory是Spring框架的基础设施,面向Spring。ApplicationContext面向Spring框架的开发者。所以咱们平时开发的过程中其实也能够发现到,咱们更多的会用上的是ApplicationContext相干的工具,而不是BeanFactory。
除此之外,在实例化这个步骤的前后,实际上还有暗藏工作,牵扯到的接口叫做InstantiationAwareBeanPostProcessor。它继承了BeanPostProcessor。可能有的人不晓得BeanPostProcessor这个接口,那么我就先介绍下这个。
BeanPostProcessor也是位于org.springframework.beans下,又叫做后置处理器,它定义了一系列的回调办法用来让使用者能够自定义Bean实例化或者依赖解析等的逻辑。它自身只有两个办法: postProcessBeforeInitialization和postProcessAfterInitialization。如办法名所说,定义Bean的初始化前后的逻辑。这个接口在整个生命周期中都有着关联。
public interface BeanPostProcessor {
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
不要弄混了BeanPostProcessor中的办法我说的是初始化前后,而生命周期的第一步是实例化。这里用到的InstantiationAwareBeanPostProcessor它有本人的对于实例化逻辑解决的两个办法。postProcessBeforeInstantiation和postProcessAfterInstantiation。
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
@Nullable
default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
return null;
}
default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
return true;
}
@Nullable
default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
return null;
}
}
通过查找调用postProcessBeforeInstantiation这个办法的中央,会追溯到创立Bean的要害办法。就是AbstractAutowireCapableBeanFactory下的createBean()。
/**
* Central method of this class: creates a bean instance,
* populates the bean instance, applies post-processors, etc.
* @see #doCreateBean
*/
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// 外面的代码我上面挑出重点的步骤一步步的贴出来
}
通过查看源码对于此办法的正文就晓得它有多重要了。它能够创立Bean的实例,对其进行属性填充,调用BeanPostProcesser等。第一步咱们留神到的代码应该是
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
它实际上是比咱们下面生命周期的图示还要之前的一步,就是获取BeanDefinition对象中的信息来对Bean class进行解析。所谓BeanDefinition,它就是对于Bean的一个形容。它蕴含了Bean的一些根底信息,如Bean的name、Bean的作用域、和其余Bean的关系等等。解析完之后再进行到下一步。
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
这个正文其实也给出了它的意义了,它给予BeanPostProcessor们一个机会,能够返回一个代理而不是指标bean的实例。但咱们翻阅到下面的InstantiationAwareBeanPostProcessor对于此办法的实现,会发现它返回的是null,所以默认的逻辑这里是不会return的。所以咱们会走到下一步,doCreateBean。
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
进入到这个办法,它的第一行正文也是简略粗犷,就是来实例化Bean的。
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
但能够发现,createBeanInstance()这个办法返回的是一个BeanWrapper对象。BeanWrapper是对Bean的一个包装,它能够设置获取被包装的对象,获取被包装bean的属性形容器等。咱们平时开发是不会间接应用这个类的。通过createBeanInstance()这个办法的正文咱们也能明确,它的作用是对于指定的bean生成一个新的实例,这里能够应用适合的实例化策略,比方工厂办法,结构器注入或者简略实例化等。
/**
* Create a new instance for the specified bean, using an appropriate instantiation strategy:
* factory method, constructor autowiring, or simple instantiation.
*/
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
//代码我也不贴了
}
接下来这段代码,正文也有阐明,就是将调用各种postProcessers来进行属性的合并,这里会进行一些注解的扫描。
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
再而后是一段跟一个面试题严密相干的代码,那就是Spring如何解决循环依赖。因为本文的重点是讲bean的生命周期,原本筹备一起写完的,但写着写着发现要说的太多了,前面我会另外独自写文章来讲述如何解决循环依赖的问题。
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
二、设置对象属性,依赖注入
完结了实例化之后,咱们持续在createBean这个办法上持续往下走,到了populateBean这一步。
// Initialize the bean instance.
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
对于这个办法,咱们已开始留神到的就是我之前说过在实例化前后都是存在着暗藏工作,下面提到了实例化之前的postProcessBeforeInstantiation,那么现在曾经实例化了,当初呈现了实例化之后的办法postProcessAfterInstantiation,这里也是给InstantiationAwareBeanPostProcessors一个机会去自定义属性被赋值后的形式。在前面代码中回去执行这个后置处理器的办法。
// 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.
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
return;
}
}
}
持续往下,咱们能看到一个相熟的单词,Autowire,不过这里是获取以后注入的形式,依据byName还是byType来取得要注入的属性。这里我也不深刻阐明了。
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
而后就是populateBean的第一步我就提到的办法,如果存在后置处理器,那么会进行属性的校验和解决,同时第二个布尔变量是用来判断是否进行依赖校验的。
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
pvsToUse = bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
if (needsDepCheck) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
checkDependencies(beanName, mbd, filteredPds, pvs);
}
最初一步,就是将后面这些步骤失去的属性进行注入了。
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
三、初始化
populateBean()办法完结后开始进入initializeBean()办法,正如办法名所表白的,就是bean的初始化。留神初始化和实例化不是一个意思,在生命周期中bean是先进行实例化再进行初始化的。
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
首先第一步,先不论那些平安机制的代码,咱们要关注的是invokeAwareMethods(beanName, bean);这行代码,这里就是调用所有的Aware类型的接口。Spring中Aware类型的接口能够让咱们获取容器中的一些资源。
private void invokeAwareMethods(String beanName, Object bean) {
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
ClassLoader bcl = getBeanClassLoader();
if (bcl != null) {
((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
}
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}
比方这外面呈现的有三种Aware类型的接口: BeanNameAware, BeanClassLoaderAware,BeanFactoryAware。它们依据bean实现了某个接口来实现不同的工作。
- 如果实现了BeanNameAware接口,则通过setBeanName()办法将beanName设置给这个bean
- 如果实现了BeanClassLoaderAware接口,则通过setBeanClassLoader()办法,将ClassLoader传入
- 如果实现了BeanFactoryAware接口,则通过setBeanFactory()办法,将BeanFactory容器实例传入
完结完Aware接口的调用,持续往下走,到了applyBeanPostProcessorsBeforeInitialization()这个办法(因为if判断是这个bean是空或者这个bean是否是synthetic的,就是是否是利用本人定义的,显然咱们本人的bean不是,所以if条件后半部分会是true)。这个办法就是解决我之前有提到过的BeanPostProcessor的postProcessBeforeInitialization()办法。如果Bean实现了BeanPostProcessor接口,那么就会执行这个办法。
之后,流程来到了invokeInitMethods()这一步,这一步就是执行bean的自定义初始化办法。如果bean实现了InitializingBean接口,就须要重写afterPropertiesSet()办法,则invokeInitMethods的时候会调用这个重写后的afterPropertiesSet()办法,如果bean自定义了init办法,则会调用指定的init办法(可通过xml中配置bean的init-method属性实现),这两个办法的先后顺序是: afterPropertiesSet在前,自定义init在后。
继续下去就是applyBeanPostProcessorsAfterInitialization()办法了,和后面的applyBeanPostProcessorsBeforeInitialization()办法前后响应,这个就不用多说了。
四、销毁
前面的一段代码还是跟解决循环依赖有关系,就先不多说,间接到最初一步,registerDisposableBeanIfNecessary().
销毁这一步其实就是能够让咱们本人自定义bean的销毁办法,用到的要害的接口是DisposableBean,它和InitializingBean接口相似,只是一个初始化阶段的init,一个是完结阶段的destroy。
/**
* Add the given bean to the list of disposable beans in this factory,
* registering its DisposableBean interface and/or the given destroy method
* to be called on factory shutdown (if applicable). Only applies to singletons.
* @param beanName the name of the bean
* @param bean the bean instance
* @param mbd the bean definition for the bean
* @see RootBeanDefinition#isSingleton
* @see RootBeanDefinition#getDependsOn
* @see #registerDisposableBean
* @see #registerDependentBean
*/
protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {
if (mbd.isSingleton()) {
// Register a DisposableBean implementation that performs all destruction
// work for the given bean: DestructionAwareBeanPostProcessors,
// DisposableBean interface, custom destroy method.
registerDisposableBean(beanName, new DisposableBeanAdapter(
bean, beanName, mbd, getBeanPostProcessorCache().destructionAware, acc));
}
else {
// A bean with a custom scope...
Scope scope = this.scopes.get(mbd.getScope());
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + mbd.getScope() + "'");
}
scope.registerDestructionCallback(beanName, new DisposableBeanAdapter(
bean, beanName, mbd, getBeanPostProcessorCache().destructionAware, acc));
}
}
}
代码示例
下面一大段一大段的源码可能看着让人有点好受,不如间接写个demo轻松一下。因为只是体现一下生命周期,那么咱们的依赖就很简略,spring-context和spring-beans即可。
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
咱们先定义一个自定义的后置处理器,为了体现初始化前后和实例化前后的流程,实现InstantiationAwareBeanPostProcessor接口,并重写postProcessBeforeInstantiation()/postProcessAfterInstantiation()/postProcessBeforeInitialization()/postProcessAfterInitialization()这四个办法。
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
System.out.println(beanName + "实例化前");
return null;
}
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
System.out.println(beanName + "实例化后");
return false;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println(beanName + "初始化前");
return null;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println(beanName + "初始化后");
return null;
}
}
再定义一个“惯例”的Bean,但咱们也为了反馈初始化和销毁的几个操作,让他实现了InitializingBean, DisposableBean, BeanNameAware三个接口。并实现对应的办法,Aware接口这里我就只实现一个了,只是为了体现注入Aware接口那个步骤。
public class DemoBean implements InitializingBean, DisposableBean, BeanNameAware {
public DemoBean() {
System.out.println("demoBean实例化");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("demoBean afterPropertiesSet");
}
public void init() {
System.out.println("demoBean init");
}
@Override
public void destroy() throws Exception {
System.out.println("demoBean destroy");
}
@Override
public void setBeanName(String s) {
System.out.println("BeanNameAware setBeanName: "+ s);
}
}
配置文件很简略,就两个bean。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<beans>
<bean name="myInstantiationAwareBeanPostProcessor" class="cn.leafw.spring.beans.MyInstantiationAwareBeanPostProcessor" />
<bean name="demoBean" class="cn.leafw.spring.beans.DemoBean" init-method="init">
</bean>
</beans>
</beans>
测试类也很简略粗犷,就单纯启动和完结。
public class Test {
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:application.xml");
applicationContext.registerShutdownHook();
}
}
点击运行,接下来就是意料之中的后果输入:
因为属性注入不不便在这外面进行测试,但大家晓得是在实例化和初始化之间就好。所以其实总的来说,Spring的生命周期了解起来不算很难,但大家对生命周期外面要害的接口或者类要有印象,ApplicationContext和BeanFactory就不必多说,BeanPostProcessor是肯定要晓得的,Spring中的很多性能的实现都跟其无关。比方@Autowired注解的原理,数据校验Validate的原理,都是有对应的处理器。
这篇博客写了我挺久的工夫,就是越写发现自己对Spring的理解越肤浅,本认为啃完了Spring文档的我应该是能轻松看懂源码,但实际上还是有点吃力的,但看懂了之后真的神清气爽,前面还会持续在这个坑里多填一点货色,学到的越多发现不会的越多,一起提高吧。
发表回复