听说你还没学Spring就被源码编译劝退了?30+张图带你玩转Spring编译
读源码,我们可以从第一行读起
你知道Spring是怎么解析配置类的吗?
配置类为什么要添加@Configuration注解?
谈谈Spring中的对象跟Bean,你知道Spring怎么创建对象的吗?
这篇文章,我们来谈一谈Spring中的属性注入
Spring中AOP相关的API及源码解析,原来AOP是这样子的
你知道Spring是怎么将AOP应用到Bean的生命周期中的吗?
推荐阅读:
Spring官网阅读 | 总结篇
Spring杂谈
本系列文章将会带你一行行的将Spring的源码吃透,推荐阅读的文章是阅读源码的基础!
前言Spring中的循环依赖一直是Spring中一个很重要的话题,一方面是因为源码中为了解决循环依赖做了很多处理,另外一方面是因为面试的时候,如果问到Spring中比较高阶的问题,那么循环依赖必定逃不掉。如果你回答得好,那么这就是你的必杀技,反正,那就是面试官的必杀技,这也是取这个标题的原因,当然,本文的目的是为了让你在之后的所有面试中能多一个必杀技,专门用来绝杀面试官!
本文的核心思想就是,
当面试官问:
“请讲一讲Spring中的循环依赖。”的时候,
我们到底该怎么回答?
主要分下面几点
什么是循环依赖?
什么情况下循环依赖可以被处理?
Spring是如何解决的循环依赖?
同时本文希望纠正几个目前业界内经常出现的几个关于循环依赖的错误的说法
只有在setter方式注入的情况下,循环依赖才能解决(错)
三级缓存的目的是为了提高效率(错)
OK,铺垫已经做完了,接下来我们开始正文
什么是循环依赖?从字面上来理解就是A依赖B的同时B也依赖了A,就像下面这样
体现到代码层次就是这个样子
@Component public class A { // A中注入了B @Autowired private B b; } @Component public class B { // B中也注入了A @Autowired private A a; }当然,这是最常见的一种循环依赖,比较特殊的还有
// 自己依赖自己 @Component public class A { // A中注入了A @Autowired private A a; }虽然体现形式不一样,但是实际上都是同一个问题----->循环依赖
什么情况下循环依赖可以被处理?在回答这个问题之前首先要明确一点,Spring解决循环依赖是有前置条件的
出现循环依赖的Bean必须要是单例
依赖注入的方式不能全是构造器注入的方式(很多博客上说,只能解决setter方法的循环依赖,这是错误的)
其中第一点应该很好理解,第二点:不能全是构造器注入是什么意思呢?我们还是用代码说话
@Component public class A { // @Autowired // private B b; public A(B b) { } } @Component public class B { // @Autowired // private A a; public B(A a){ } }在上面的例子中,A中注入B的方式是通过构造器,B中注入A的方式也是通过构造器,这个时候循环依赖是无法被解决,如果你的项目中有两个这样相互依赖的Bean,在启动时就会报出以下错误:
Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference?为了测试循环依赖的解决情况跟注入方式的关系,我们做如下四种情况的测试
依赖情况 依赖注入方式 循环依赖是否被解决AB相互依赖(循环依赖) 均采用setter方法注入 是
AB相互依赖(循环依赖) 均采用构造器注入 否
AB相互依赖(循环依赖) A中注入B的方式为setter方法,B中注入A的方式为构造器 是
AB相互依赖(循环依赖) B中注入A的方式为setter方法,A中注入B的方式为构造器 否
具体的测试代码跟简单,我就不放了。从上面的测试结果我们可以看到,不是只有在setter方法注入的情况下循环依赖才能被解决,即使存在构造器注入的场景下,循环依赖依然被可以被正常处理掉。
那么到底是为什么呢?Spring到底是怎么处理的循环依赖呢?不要急,我们接着往下看
Spring是如何解决的循环依赖?关于循环依赖的解决方式应该要分两种情况来讨论
简单的循环依赖(没有AOP)
结合了AOP的循环依赖
简单的循环依赖(没有AOP)