什么是循环依赖?#
当有两个bean,分别用set方法依赖对方。就会造成循环依赖,如:
1 |
|
背景----三级缓存快速入门#
看一个对象DefaultSingletonBeanRegistry,他是DefaultListableBeanFactory的父类,里面有三级缓存:
1 | // 一级缓存,存放实例化并初始化完毕的bean |
实例化过程#
背景,默认BeanPostProcessor#
先来混个脸熟悉,下面过程中会看到他们
历史已有BPP:4个#
- org.springframework.context.support.ApplicationContextAwareProcessor------------给我们注入AC对象、BF、env等各种aware
- org.springframework.boot.web.servlet.context.WebApplicationContextServletContextAwareProcessor---------web环境注入Web的AC对象的
- org.springframework.context.support.PostProcessorRegistrationDelegate$BeanPostProcessorChecker----------
- org.springframework.context.annotation.ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor
- 用于给注解完成配置,如
@EnableRedisHttpSession(redisNamespace = “web:session”),可以
- 用于给注解完成配置,如
依次注册:#
@PriorityOrdered:
- org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor
@Ordered
- org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator
- AOP代理生成
- org.springframework.boot.web.server.WebServerFactoryCustomizerBeanPostProcessor
- org.springframework.boot.web.server.ErrorPageRegistrarBeanPostProcessor
- org.springframework.context.annotation.CommonAnnotationBeanPostProcessor
- 完成Javax的@Resource等通用注解的metaFata解析,并链式依赖注入
- org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
- 完成@Autowired等注解的MetaData 解析,并链式注入
- org.springframework.context.support.ApplicationListenerDetector
Bean创建过程#
- 我们的
abstractContext
里面的refresh方法经过一系列的扫描解析,把BeanDefinition
获取到BeanFactory中去。同时执行一大堆BeanDefinitionRegistryPostProcessor
,和BeanFactoryPostProcessor
去控制我们的BeanDifinition的生成行为。在refresh的registerBeanPostProcessors
方法中注册了一堆BeanPostProcessor,然后会来调用此处的beanFactory.preInstantiateSingletons()
: - BF的
preInstantiateSingletons
方法循环所有的beanName(比如有a,b,c三个bean):- 拿出Merged
RootBeanDefinition
去getBean: - FactoryBean去创建
doGetBean
(&beanName)、普通bean去doGetBean
(beanName):- 先去执行一次第一个
getSingleton(beanName);
看看有没有之前被放进去过(比如被循环依赖,或者被@DependsOn创建过),正常会返回null - 拿到beanFactory,在set标记为正在创建中,开始继续创建
- 拿到beanDefinition,判断里面的@DependsOn,如果有,先
getBean
递归创建依赖的对象 - 调用下面第二个
getSingleton(beanName, () -> {return createBean(beanName, mbd, args);})
,传入一个createBean
的lambda参数的匿名内部类。:- 下面第二个
getSingleton
里面的逻辑:对一级缓存加锁,尝试去拿一下。 - 拿不到就先
beforeSingletonCreation(beanName);
调用一个回调,由子类BF实现 singletonFactory.getObject()
调用匿名类的lambda表达式里面的createBean方法去创建对象:createBean
方法先从bd解析出class- 调用BeanPostProcessor,来看看有没有谁能返回一个对象
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
,如果某个BPP返回了对象,就直接丢回去。(此处明显是创建一个代理对象,AOP在此实现) - 如果上一步没有哪个BPP返回代理对象,调用
doCreateBean(beanName, mbdToUse, args);
创建并返回一个bean:- doCraeteBean里面就使用
createBeanInstance
方法去反射创建对象(FactoryBean
是getObject和普通Bean不一样,同时BPP可以决定构造方法),创建的对象是空的,没有设值。-----------------刚刚实例化,还没放到BF中 - 然后
applyMergedBeanDefinitionPostProcessors
执行了MergedBeanDefinitionPostProcessor
,比如CommonAnnotationBeanPostProcessor
去检测@Resource这种Java.injection的注解生成metadata、AutowiredAnnotationBeanPostProcessor
去检测了@Auowired
这种Spring的注解,生成他们的metadata,可以去改一次bd的信息。 boolean earlySingletonExposure
解决循环依赖第一步:- 如果true,然后调用了
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
,把getEarlyBeanReference
这个ObjectFactory
函数式接口放到三级缓存{k:a, v:匿名类},并把二级缓存删掉(有的话)---------此时bean算是实例化完毕并放到三级缓存中,接下来是初始化过程
- 如果true,然后调用了
- 调用
populateBean(beanName, mbd, instanceWrapper)
填充bean:- 执行
InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation
回调,允许spring填充前改变bean的属性。默认都是null。 - 循环依赖,根据注入类型,执行
autowireByName(beanName, mbd, bw, newPvs);
或者autowireByType(beanName, mbd, bw, newPvs);
进行注入,拿到propertyValue - 遍历BPP(此时都是
InstantiationAwareBeanPostProcessor
),执行postProcessAfterInstantiation
:CommonAnnotationBeanPostProcessor
会postProcessProperties
去解析之前@Resource
属性的metadata,调用InjectMedadata.inject
、使用doResolveDependency
去getBean拿到PropertyValues递归注入AutowiredAnnotationBeanPostProcessor
会postProcessProperties
去解析之前@Auowired
属性的metadata,doResolveDependency
去getBean拿到PropertyValues递归注入- xml的setter是拿到propertyValue去注入,和上面类似。
- 假设A里面是
@Autowired B
B里面也是@Autowired A
,的循环依赖此时正在解析A的时候发现了B,会再去getBean(B) (此时三级a):- B创建完毕放到三级缓存。此时(三级a,b:获取对象的一个匿名内部类)
- B来
populateBean
的时候到达这里就会需要注入A,到达这里就会再getBean(A):- 调用地一个getSingleton方法,会拿到A的匿名类的三级缓存
getEarlyBeanReference(beanName, mbd, bean)
,从三级缓存里面拿出来实例化还未初始化的A对象a,并把它转移到二级缓存中。(此时二级a,三级b) - 然后给B对象的a属性赋值a的早期对象
- 然后B创建完毕放到三级缓存,返回并注册(此时一级b:完全状态实例化和初始化都结束,二级a:创建中,实例化未初始化状态)
- 调用地一个getSingleton方法,会拿到A的匿名类的三级缓存
- A设置b,返回注册(此时一级a,b,都是完全状态)
- 执行
afterSingletonCreation(beanName);
方法,留给子类BF拓展 addSingleton(beanName, singletonObject);
- 执行
- 初始化initializeBean:
exposedObject = initializeBean(beanName, exposedObject, mbd);
得到一个可以暴露的对象:-----------------AOP- 如果class是Aware,给他塞BF、ClassLoader:
- 1.
applyBeanPostProcessorsBeforeInitialization
:执行所有BPP的BeforeInit方法:- 如果实现了Aware,
invokeAwareMethods
方法ApplicationContextAwareProcessor
里面塞各种Aware,如context
、env
ImportAwareBeanPostProcessor
的postProcessBeforeInitialization
给我们的Bean塞进去注解上metadata
- 如果实现了Aware,
- 2.
invokeInitMethods
- 执行
@afterPropertiesSet
这个init
方法
- 执行
- 3.
applyBeanPostProcessorsAfterInitialization
--------AOP在此实现postProcessAfterInitialization
执行,其中ApplicationListenerDetector
去检查这个类是否是一个监听器,是的话加入到applicationContext
里面AbstractAutoProxyCreator
的postProcessAfterInitialization
方法调用了wrapIfNecessary去创建代理:- 拿到这个类的切面,有才继续调用
createProxy
方法创建代理:- 给bd的
origianlTargetClass
塞进去代理前的类名,new 一个ProxyFactory
- 拿到这个类的接口,遍历每一个,只要找到一个非InitializingBean
、
Closeable、
Aware`等无需代理的接口、就继续 - 有接口就加到proxyFactory中,没有的话就设置代理class标识为true(后面判断jdk还是cglib)
buildAdvisors
构建切面拦截的列表,添加到proxyFactory
中- 提供一个扩展点
customizeProxyFactory(proxyFactory);
createAopProxy().getProxy(clazzLoader)
就创建代理:- 调用
DefaultAopProxyFactory#createAopProxy(AdvisedSupport config)
创建动态代理:- 如果有接口
new JdkDynamicAopProxy(config)
,创建JDK动态代理,InvocationHandler,拦截invoke方法 - 没有接口
new ObjenesisCglibAopProxy(config)
,创建CGlib动态代理,enhancer增强器塞接口/属性/类、设置callback、method intercepter
- 如果有接口
- 调用
- 给bd的
- 拿到这个类的切面,有才继续调用
- 调用第一个getSingleton(name,false),只从1、2拿,是null,然后
registerDisposableBeanIfNecessary
是个空 - 结束doCreateBean,得到一个BeanWarper包装类
- doCraeteBean里面就使用
- 结束CreateBean,getBean一次去从三级getSingleton缓存拿出来
- 发现是新的bean,
addSingleton(name,bean)
,注册到一级缓存,清除二级三级缓存。 afterSingletonCreation(String beanName)
留给子类BF实现拓展
- 结束getSingleton
- 下面第二个
- 结束doGetBean
- 先去执行一次第一个
- 结束getBean
- 拿出Merged
- 继续循环创建下一个对象
核心方法摘录说明#
doGetBean方法#
AbstractBeanFactory是DefaultSingletonBeanRegistry的一个子类,中有一个doGetBean
方法承接了外面的各种getBean
的调用,是每一个单例对象创建的具体实现方法:
1 | // 真正创建一个Bean |
createBean 上面lambda表达式来创建自己的核心方法#
这个方法非常简单:
- 从beanDefinition拿出Class
- 可以允许
BeanPostProcessor
创建代理对象resolveBeforeInstantiation(beanName, mbdToUse)方法如果返回对象,就丢回去。- 其实就是拿到所有的
InstantiationAwareBeanPostProcessor
子类,最主要的AOP类AbstractAutoProxyCreator#postProcessBeforeInstantiation
里面进行createProxy
方法找到ProxyFactory类
,调用AopProxy#createAopProxy
方法,有两个实现
- 其实就是拿到所有的
- 否则继续后面的
doCreateBean
去使用lambda
表达式真正创建
1 |
|
doCreateBean#
1 | protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) |
addSingleton 添加一级缓存#
清空二级三级缓存
1 | protected void addSingleton(String beanName, Object singletonObject) { |
addSingletonFactory添加三级缓存#
1 | protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) { |
addSingleton添加一级缓存#
1 | protected void addSingleton(String beanName, Object singletonObject) { |
各个重载的getSingleton#
第一个getSingleton(beanName, boolean allowEarlyReference) ,依次从一级、二级、三级拿。三级的ObjectFactory.getObject升级到二级。#
初次过来这里会返回null,各级缓存都没有,没有则返回。
1 | // 返回初始化好的bean,或者实例化还未初始化的二级缓存。同时从三级缓存remove |
第二个getSingleton(beanName, ObjectFactory<?> singletonFactory) ,传入ObjectFactory这个lambda表达式#
1 | /** |
getEarlyBeanReference 获取三级缓存早期对象#
如getBean( A) --populate–>getBean( B)–populate—>getBean( A)的时候,去到getSingleton(A)发生循环引用,从三级缓存里面调用过来:
// getEarlyBeanReference(“a”, bd, a@123对象)
1 | /** |
AOP实现#
-
我们的
@EnableAspectJAutoProxy
注解的Config类是一个@Configuration
会在refresh的invokeBeanFactoryPostProcessors
中被ConfigurationClassPostProcessor
识别到。使用import技术扫描加载@Import(AspectJAutoProxyRegistrar.class)
。(见spring启动流程文章) -
使用
AspectJAutoProxyRegistrar
里面的ImportBeanDefinitionRegistrar
实现去拿到beanDifinitionReigistry(其实就是BF),注入了一个AnnotationAwareAspectJAutoProxyCreator
这个BeanPostProcessor -
然后在refresh的实例化bean方法
finishBeanFactoryInitialization(beanFactory);
中的doCreateBean中先反射创建对象,然后的initBean里面初始化:- 执行BPP的beforePostProcessor方法
- 执行init方法(@PostConstruct)
- 执行后置处理器去调用上面这个BPP的
postProcessorAfterBeanInit
完成代理。
1 | public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport |
DefaultAopProxyFactory的createAopProxy(AdvisedSupport config) 真正创建代理#
1 | public class DefaultAopProxyFactory implements AopProxyFactory, Serializable { |
QA#
- 一级缓存能解决么?
- 不行,因为如果只有一级缓存,创建中(实例化还没初始化)的对象和创建结束的对象都在一个map中,可能导致正在创建中的对象被用户提前获取属性为空,导致空指针。此时可以加一个二级缓存来存放还没初始化完毕的对象。
- 为什么一定要三级缓存?二级不就行了么?
- 三级里面放的是一个匿名内部类,包装了一个刚刚实例化的对象。
getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean)
,调用了BPP去进行判断,我们的对象是简单对象还是需要进行代理的。 - 三级缓存的主要意义:代理。比如
AbstractAutoProxyCreator#getEarlyBeanReference,里面wrapIfNecessary进行createProxy创建代理
,我们的对象在向三级缓存放置之后,可以在读取的时候通过pambda表达式去执行BPP的方法,给BPP一个机会来判断是否需要进行代理,选择代理方式进行代理。 - 生成代理之后我们用户使用都应该是代理对象,如果不放到三级缓存,可能代理之前被获取到原始对象,导致代理失败。放了三级缓存之后,只要有人去拿就会判断是否代理,不会造成代理目标逃逸,代理失败的情况。也就是保证了不管什么时候获取的对象都是代理过的。
- 三级里面放的是一个匿名内部类,包装了一个刚刚实例化的对象。