生命周期
流程梳理:
-
创建ApplicationContext,设置原始的RootBeanDefinition,开始加载BeanDefinition。
- springboot中通过
main()函数的run()方法会开始进行容器的创建,通过createApplication()方法会去创建一个ApplicationContext容器,默认的类型为AnnotationConfigApplicationContext,创建容器的构造方法里,会直接放进去几个RootBeanDefinition,其中有一个BeanDefinition的的类型为ConfigurationClassPostProcessor,算是一个开天辟地的类,在spring的主流程refresh()的方法里的invokeBeanFactoryPostProcessors(beanFactory)会去调用这个后置处理器,其实是会利用beanFactory获取后置处理器的单例实例,然后去调用实例化后的ConfigurationClassPostProcessor这个后置处理器的postProcessBeanDefinitionRegistry方法。在此之前的run()方法里的prepareContext()会把启动的Main方法的类加入到原始的BeanDefinition里面,因为在ConfigurationClassPostProcessor这个后置器的工作过程中,首先回去加载这个主类,因为这个主类上有@Configuration所以他会直接去加载这个主类,然后解析这个配置类的过程中他会看是不是有@ComponentScan这个注解,如果有这个注解又回去扫描这个basepackage下面所有加了@Component@Service这些注解的类,然后把这些class文件用classloader读取出来,包装成BeanDifinition放到Map里面缓存起来。
- springboot中通过
-
通过BeanDefinition开始实例化原始对象
- 上一步其实把原始需要的其他BeanPostProccessor已经都添加到单例池了,后面就是开始加载各种我们标记
@Component@Service等托管给Spring的Bean了,触发的方法在refresh()方法的finishBeanFactoryInitialization(beanFactory)中。这里会判断单例池中有没有这个Bean没有的话就会去创建这个Bean调用到对应工厂类的createBean()的方法,在反射调用的实例化原始对象之前,会调用到会第一次调用到一个后置处理器,org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.resolveBeforeInstantiation(),这个方法里会调用后置处理器方法InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation,主要是为了判断这个加载的Bean是不是需要AOP的功能,因为这里涉及到循环依赖三级缓存的问题(后面说)。之后会在再次调用后置处理器,第二次调用后置处理器,org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory #determineConstructorsFromBeanPostProcessors这个方法会调用后置处理器SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors这个后置处理器主要是为了推断出调用的是这个Class类的哪个构造方法去实例化这个原始对象。完成后就会通过反射去实例化对象。然后会进行第三次调用后置处理器,org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory #applyMergedBeanDefinitionPostProcessors方法会调用MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition后置处理器的方法,他的主要的目的就是为了合并父子BeanDefinition,因为BeanDefinition就是为了在Bean的创建过程中定义一些特殊的操作,并且还支持父子继承的关系,在这里就允许你改里面的属性,比如scope其实是可以在这里修改到底是单例的还是原型的,这也是一个扩展点。然后,会第四次调用后置处理器,org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory #getEarlyBeanReference方法,会调用后置处理器SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference,这个后置处理器主要是为了解决循环依赖,用一个工厂方法把原始对象包装起来,这个工厂可以生产一个AOP的代理类,提前将原始对象AOP增强。后面会说解决循环依赖的具体过程。
- 上一步其实把原始需要的其他BeanPostProccessor已经都添加到单例池了,后面就是开始加载各种我们标记
-
属性注入
- 在创建完原始对象后,会调用
populateBean()方法进行属性注入,这时候会第五次调用后置处理器,org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory #populateBean方法中会调用InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation,这个后置处理器主要是为了判断这个BeanDefinition是否允许属性注入,如果允许属性注入会开始第六次调用后置处理器,同样在populateBean()方法中,会调用InstantiationAwareBeanPostProcessor#postProcessProperties,来进行依赖属性或者Bean的加载注入,执行属性注入@Autowired和@Resource。
- 在创建完原始对象后,会调用
-
初始化阶段xxxAware
- 在
initializeBean()方法中,首先会进行三个Aware接口的注入,调用invokeAwareMethods()注入了,BeanNameAware BeanClassLoaderAware BeanFactoryAware,注入完成之后。会第七次调用后置处理器,org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory #applyBeanPostProcessorsBeforeInitialization方法,会调用后置处理器BeanPostProcessor#postProcessBeforeInitialization,他的主要功能就是完成其他Aware接口的调用注入,也会调用@PostConstructor注解的方法,运行用户指定的逻辑。然后会运行invokeInitMethods()方法,如果执行Bean中实现了的InitializingBean.afterPropertiesSet()的方法,那么就调用这个,或者如果在XML配置中指定了init-method属性的方法,那么就调用这个,总之就是进行初始化。
- 在
-
AOP代理
- 上面的步骤,其实已经完成了一个Bean的实例化属性注入初始化,还有最后一个步骤就是如果指定了AOP增强,那么就要为这个Bean生成代理的AOP代理对象,这时候会第八次调用后置处理器,
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory #applyBeanPostProcessorsAfterInitialization方法会调用postProcessAfterInitialization,这里是为了实现动态代理Proxy和用户自己定义的BeanPostProsessor的after方法的地方,是的,你可以继承BeanPostProsessor然后自己实现After方法。
- 上面的步骤,其实已经完成了一个Bean的实例化属性注入初始化,还有最后一个步骤就是如果指定了AOP增强,那么就要为这个Bean生成代理的AOP代理对象,这时候会第八次调用后置处理器,
最后,会把Aop代理的类扔到单例池里,就可以使用了,最后还有一个Bean销毁的过程,其实比较简单就不说了。
从上面可以看到整个生命周期调用了八次后置处理器,这八个后置处理器用户都可以进行重写接口方法实现自己的逻辑。
- 第一次调用后置处理器:
- 作用:判断正在实列化的bean是否需要被代理
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory #resolveBeforeInstantiation - 后置处理器和方法:
InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation
- 第二次调用后置处理器:
- 作用:推断创建这个bean的构造方法
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory #determineConstructorsFromBeanPostProcessors - 后置处理器和方法:
SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors
- 第三次调用后置处理器:
- 作用:合并BeanDefinition
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory #applyMergedBeanDefinitionPostProcessors - 后置处理器和方法:
MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition
- 第四次调用后置处理器:
- 作用:循环依赖,暴露一个工厂,用这个工厂去获取bean的实例
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory #getEarlyBeanReference - 后置处理器和方法:
SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference
- 第五次调用后置处理器:
-
作用:属性注入,判断这个BeanDefinition 是否允许属性注入
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory #populateBean -
后置处理器和方法:
InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation
- 第六次调用后置处理器:
-
作用:执行属性注入 @Autowired和@Resource
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory #populateBean -
后置处理器和方法:
InstantiationAwareBeanPostProcessor#postProcessProperties
- 第七次调用后置处理器:
- 作用:调用各种Aware接口和执行@PostConstruct 和我们自己的实现beanPostProcessor的before方法的地方
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization - 后置处理器和方法:
BeanPostProcessor#postProcessBeforeInitialization
- 第八次调用后置处理器:
-
作用:动态代理Proxy和我们自己的实现beanPostProcessor的after方法的地方
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory #applyBeanPostProcessorsAfterInitialization -
后置处理器和方法:
postProcessAfterInitialization
循环依赖
循环依赖的问题描述比较简单,比如:
class A{
@Autowired
B b;
}
class B{
@Autowired
A a;
}
其实就是A依赖了B,B依赖了A,因为其实spring去加载类的时候其实是一个单线程再跑,有先后顺序的,那么先加载哪一个,都会因为另一个没有创建完毕而不能注入属性。 因为Bean的声明周期是(简化):
- class-->BeanDefinition
- 反射创建原始对象 new A();
- 注入依赖
- 各种Aware调用
- 初始化
- AOP
- 放入单例池
在这个过程中,只有放入了单例池才算是创建出来一个完整的Bean,才能够被其他Bean注入。所以当A B相互依赖的时候,各自都不是一个完整的Bean,都不能被对方注入。
解决循环依赖主要用到了下面几个Map:
- 用来保存正在创建中的对象的名
- 一级缓存,已经完成创建的Bean的单例池
- 原始对象的缓存缓存Map
- 缓存了包含了原始对象的工厂
下面来过一下这个三级缓存是怎么参与生命周期的:
-
首先,进行Bean A的加载,从class变成Beandefinition。
-
然后把A的Bean那么放到正在创建中的缓存中,也就是
singletonsCurrentlyInCreation这个Set里面。 -
然后会把A进行反射实例化获得A的原始对象,这个时候回去判断是不是允许进行三级缓存,如果允许,会把刚创建出来的原始对象,外层包装上一个工厂方法,为了可以提前进行AOP。如果不允许的化就会只把对象放到二级缓存的
earlySingletonObjects里面,所以这里可以看到,如果开启了允许三级缓存,那么会把创建的原始对象从二级缓存中移除,包装一层工厂后放到三级缓存里。做完这些之后会开始进行属性注入,这个时候会发现需要注入Class B,就会进行B的声明周期的创建。
-
B的声明周期开始,前三步和A一样,也是进行加载创建原始对象,然后开始进行初始化,但是这时候获取A的时候回去查看正在创建中的Set的BeanName,发现A正在创建,判断出来发生了循环依赖,然后开始去单例池里面找,找不到,到二级缓存里面找找不到,到三级缓存里面找,找到了调用工厂的getObject方法,获取到A的代理对象,并且把A从三级缓存里删除放到二级缓存里,因为已经创建出来代理对象了,三级缓存就没必要了。
-
这个时候B已经完成了依赖注入,后续声明周期初始化包括他自己的AOP按正常进行。最后放到单例池里。
-
B完成创建之后,会回到A的属性注入这里来,然后在单例池中把B取出来,进行属性注入。
-
完成之后会进行Aware注入和初始化,但是到AOP这里的时候,他其实回去二级缓存里判断,因为之前A已经提前进行了AOP增强,所以这里不会在进行AOP,会直接二级缓存里的对象删除,放到单例池里,完成自己的加载。
简化版: ClassA:
- class-->BeanDefinition
- 放到创建中的缓存Set中
- 根据反射实例化对象,并将原始对象用工厂包装放到三级缓存中。
- 依赖注入-->获取B对象-->一级缓存单例池查找-->二级缓存提前暴露的原始对象中查找-->三级缓存包含了原始对象的工厂缓存中查找-->创建B对象
- Aware注入
- 初始化
- AOP代理,判断是否之前已经进行了代理,如果进行则不调用AOP代理
- 放入单例池
ClassB:
- class-->BeanDefinition
- 放到创建中的缓存Set中
- 根据反射实例化对象,并将原始对象用工厂包装放到三级缓存中。
- 依赖注入-->获取A对象-->一级缓存单例池查找-->二级缓存提前暴露的原始对象中查找-->三级缓存包含了原始对象的工厂缓存中查找-->调用工厂方法获取到A对象,注入,并且移除三级缓存,将A放到二级缓存中。
- Aware注入
- 初始化
- AOP代理
- 放入单例池
二级缓存和三级缓存
其实二级缓存已经可以解决循环依赖了,因为已经将早起的原始对象放到Map缓存了,B如果需要获取直接从二级缓存就可以获取出来了,使用三级缓存主要是为了AOP增强,因为AOP增强是需要生成代理对象的,而在生命周期中,AOP的代理增强的创建是在属性注入之后的,这时候B对象已经注入了A的原始对象,而且已经放到单例池了,所以需要提前进行AOP,所以才引入了三级缓存解决这个问题。
在一个是三级缓存可以接觉Setter的注入,但是构造器的注入是在反射实例化的对象的时候就需要吧依赖的对象给放进去了,这个时候是没有办法解决循环依赖的问题的,拿A B 两个class来说 我在创建A的原始对象的时候就需要一个完整的B,但是在B创建的时候又需要A,这是个死循环,所以没有办法解决,不过可以懒加载的办法,让其中一个类在用的时候加载而不是在一个启动线程里去同时创建,这就能解决这个问题。