一个两个以上的bean互相持有对方,比如A持有B B持有A.
Spring 注入bean 的方式有 field 属性注入 ,构造器注入
field属性注入-这个例子会正确执行
@Service
public class A {
@Autowired
private B b;
}
@Service
public class B {
@Autowired
private A a;
}
原理
Spring 在创建 bean 的时候并不是等它完全完成,而是将创建中的 bean 提前曝光(即加入到 singletonFactories 三级缓存中),当下一个 bean 创建的时候需要依赖此 bean ,则从三级缓存中获取。
Spring创建一个Bean的时候,不是完全完成了,而是将这个bean提前加入singletonFactories三级缓存,下一个bean创建以来这个Bean的时候,可以从三级缓存获取。
singleton: 单身的,单独的
构造器注入例子--这个例子将报错
@Service
public class A {
private B b;
@Autowired
public A(B b) {
this.b = b;
}
}
@Service
public class B {
private A a;
@Autowired
public B(A a) {
this.a = a;
}
}
Relying upon circular references is discouraged and they are prohibited by default. Update your application to remove the dependency cycle between beans. As a last resort, it may be possible to break the cycle automatically by setting spring.main.allow-circular-references to true.
解决方案1.CGLIB 动态代理
@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS) // 使用 CGLIB 动态代理
@Service
public class B {
private A a;
@Autowired
public B(A a) {
this.a = a;
}
}
@Scope 注解是 Spring IOC 容器中的一个作用域,默认为 singleton(单例)。通过 Scope 中的 proxyMode 属性可以设置类的代理模式,
DEFAULT 不使用代理
NO 不使用代理
INTERFACES 使用 JDK 动态代理
TARGET_CLASS 使用 CGLIB 动态代理
这里我们不对 @Scope 做过多介绍,上边代码中因为 B 类没有实现接口,不能使用 JDK 动态代理,所以这里使用的是 CGLIB 动态代理。
解决方案2.Lazy
@Autowired
public B(@Lazy A a) {
this.a = a;
}
这两种方式又是如何解决循环依赖问题的呢?
其实它们 都是通过动态代理来避免了循环依赖。
我们再来描述一下 解决循环依赖的过程:
P1. 创建 A 时需要 B ,发现 B 是可以延迟加载或者是指定了代理模式的;
P2. 创建一个 B 类的代理类 Bproxy ;
P3. 通过 Bproxy 创建 A(此时 A 的依赖关系已经变成了 A 依赖 Bproxy);
P4. 再创建 B 时,A 已经存在,所以 B 也成功创建。
三种Spring Autowired比较【https://www.cnblogs.com/mili0601/p/15582421.html】
https://developer.aliyun.com/article/766880
https://blog.csdn.net/daidaineteasy/article/details/115559725
延伸问题
1.什么是AOP
2.什么是Bean
3.什么叫反射 https://blog.csdn.net/qq_51515673/article/details/124830558