Spring的循环依赖问题
循环依赖就是,一个组件依赖于另一个组件。类似
@Component
public class A {
@Autowired
private B b;
public A(B b) {
this.b = b;
}
}
@Component
public class B {
@Autowired
private A a;
public A(A a) {
this.a = a;
}
}
如果要创建A对象,因为构造函数有B属性,要创建B对象,那么需要将A对象注入。
就造成了循环依赖问题。
(因为如果只有有参构造器,那么没有无参构造器,要创建对象需要传入参数才能完成创建。)
解决的方法很明显:
-
添加空构造函数,此时可以把参数式构造函数去掉
@Component public class A { @Autowired private B b; // 添加空构造函数 public A() { } // 可以去掉,也可以保留,反正spring不会用到。 public A(B b) { this.b = b; } } @Component public class B { @Autowired private A a; // 添加空构造函数 public B() { } // 可以去掉,也可以保留,反正spring不会用到。 public B(A a) { this.a = a; } }
-
修改字节码,把构造函数改为不需要传参的构造函数
我不知道能否通过asm来修改字节码来实现把构造函数修改,但是如果想要修改类定义的构造函数,貌似只能通过修改生成的字节码了。
-
直接在属性上面加上
@Autowired
注解,spring会通过反射来注入对象的。@Component public class A { @Autowired private B b; } @Component public class B { @Autowired private A a; } @Configuration @ComponentScan(basePackages = "inject.dep2") @EnableAspectJAutoProxy(proxyTargetClass = true) public class Config { } class ATest { ApplicationContext context = new AnnotationConfigApplicationContext(Config.class); @Test public void test () { A a = (A) context.getBean("a"); System.out.println(a); } }
结果是可以注入成功。
spring采用三级缓存来解决循环依赖的问题,但是我个人感觉好像无需三级缓存,不过三级缓存能把整个过程表现地更清晰罢了。
个人说明:
我个人制作的简易框架中,没有用到三级缓存,但是也实现了属性的注入。
主要是因为,默认情况下,ioc控制的对象是单例的,那么在初始化bean时,
比如:A发现有属性B,从IOC的map中获取B对象,没有B对象,可以先调用B对象的无参构造方法创建B对象,然后等到B对象注入属性的时候,从Map中获取A对象注入即可。
这样,不就解决了循环依赖的问题吗?
我个人的实现就是采用的最简单的方式,不过应该有不足之处,Spring采用三级缓存解决这种问题,肯定有好处,而且可以使代码更加清晰。
不过我当时没考虑循环依赖,但是我个人觉得单例模式下,采用map的IOC容器天然就可以解决循环依赖的问题。
我个人写的微型框架summer,实现了基本的功能,但是暂时注释比较少,后续我会加上
如果只是对于基本的IOC容器的实现有兴趣,可以查看我写的这篇博客
-
采用setter来解决。对于需要注入的属性无需标记
@Autowired
,只需要将需要注入的属性写上setter方法,spring就可以注入。@Component public class A { private B b; public void setB(B b) { this.b = b; } } @Component public class B { private A a; public void setA(A a) { this.a = a; } }
以上都是建立在单例模式的基础上,如果采用多例模式,每次都需要创建新的对象的话,可想而知,无法通过ioc容器来实现循环依赖的解决、
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class A {
@Autowired
private B b;
}
@Component()
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class B {
@Autowired
private A a;
}
测试依旧会报错:询问你是否有循环依赖
以上就是我个人对于spring循环依赖的理解,如果有任何不对的请各位指出,我将悉心查验并改正。