这篇文章主要会讲述代理Bean的整个加载过程,与普通Bean的加载过程,但是还是会有一些的区别。接下来讲述关于代理Bean的整个流程,和普通Bean类似的流程就不讲述了,可以看看往期文章。
1.代理Bean的加载
代理Bean的加载主要是在初始化后的后处理器阶段完成创建代理Bean,此时目标类加载过程已经基本完成。代理Bean不会对目标Bean中的属性进行注入,他只会将目标Bean注入,到时需要通过属性去调用的时候可以直接拿到目标Bean中的属性去调用,因为目标Bean中所有的Bean都已经完成了属性填充了。

生成代理的逻辑主要来自于AbstractAutoProxyCreator###postProcessAfterInitialization
,该方法内部有个方法wrapIfNecessary
会判断是否需要生成代理对象,判断的标准是该Bean是否存在通知,也就是我们所熟知的增强逻辑,同时会将高级Aspect切面转成低级Advisor切面。最后将代理对象放入单例池中,同时删除第二、三级缓存。

2.代理Bean循环依赖
循环依赖一定是ProxyBeanA填充属性时注入ProxyBeanB时发生的,这时会发现ProxyBeanB不存在,然后进行加载ProxyBeanB的逻辑,在ProxyBeanB中需要注入ProxyBeanA的属性,此时第三级缓存就发挥了作用,这个第三级缓存会返回该Bean的一个Bean工厂lambda表达式,该表达式() -> getEarlyBeanReference(beanName, mbd, bean)
可以返回一个半成品的普通Bean或者是代理Bean,这时循环打破,ProxyBeanB成功将ProxyBeanA(代理对象)注入。
代理Bean循环依赖时,创建代理Bean的时机改变了:正常是在初始化后完成的,但是出现循环依赖后,ProxyBeanB去获取ProxyBeanA时,在三级缓存中拿到lambda的表达式进而执行完拿到代理对象,这时对于ProxyBeanA而言还是处于属性填充阶段,因此创建时机变了。代理Bean循环依赖时,依然基于普通Bean完成创建:在发生循环依赖时,提前创建的代理Bean会是在属性填充阶段,当完成循环依赖时,还需要继续从属性阶段开始完成后续的初始化,这时完成初始化的Bean并不是代理Bean,而是普通Bean,在完成了所有的初始化(执行后处理的步骤)后,会将第二级缓存中的代理Bean 取出来放入第一级缓存。

代理Bean提前创建时,后期不在重复创建: 发生循环依赖时,会执行其中的一个Bean(最初加载的Bean)的工厂的Lambda的表达式,在执行该表达式时,会将该bean缓存到earlyProxyReferences中,然后后期在再次创建的时候会检查该Map中是否存在即可。


代理Bean出现循环依赖一定需要三级缓存吗?
不一定。我理解如果只是单纯考虑循环依赖的话,完全可以去掉第二级缓存。创建完的代理对象(半成品)放入第一级缓存对象。我个人认为三级缓存的意义是为了更加清晰地划分bean的生命周期,另外第三级缓存的作用也是为了延迟创建代理而生。
针对代理Bean循环依赖,删除第二级缓存的实践 GitHub地址 下载后找到EmbedTomcatApplicationStarter进行启动。
代理Bean和普通Bean的要求不一样:前者要求构造器不能不为private的,后者都可以,报错原因如下:


3.总结
最后用一张图来总结整个代理Bean的创建过程。

原文始发于微信公众号(处女座码农):Spring—代理对象加载
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/251617.html