是这样的,有个实习生朋友问了我循环依赖的问题,我将Spring内部的三级缓存原理都跟他说了,并保证Spring已经解决了这个问题,然后他扔了一道题给我,说报错了。
好家伙,感情是想我让我查bug
你们看看?
@Component
public class A {
private final B b;
public A(final B b) {
this.b = b;
}
public void print() {
System.out.println("in a");
}
}
@Component
public class B {
private final A a;
public B(final A a) {
this.a = a;
}
public void print() {
System.out.println("in b");
}
}
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'a' defined in file [C:\soft\code\common\MongodbDataTest\dbDataTest\target\test-classes\com\db\model\A.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'b' defined in file [C:\soft\code\common\MongodbDataTest\dbDataTest\target\test-classes\com\db\model\B.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference?
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:800)
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:229)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1354)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1204)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:564)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:944)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:782)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:774)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:439)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:339)
at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:123)
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:99)
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124)
... 68 more
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'b' defined in file [C:\soft\code\common\MongodbDataTest\dbDataTest\target\test-classes\com\db\model\B.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference?
这TM,原来Spring并没有解决构造器循环依赖
难道,spring对于这种循环依赖真的束手无策了么?
其实不是的,spring还有@Lazy这个大杀器...只需要我们对刚刚那两个类小小的改造一下:
![](https://i-blog.csdnimg.cn/blog_migrate/6a1f9f2958d0d133a5480c69fd8e1375.png)
❝lazy为啥可以解决这个问题?
❞
反调@Lazy注解可以看到
![](https://i-blog.csdnimg.cn/blog_migrate/2d75ceb32ec3b626dc7a5a9b924118eb.png)
从源码我们可以看到,对于@Lazy的依赖,我们其实是返回了一个代理类(以下称为LazyProxy)而不是正真通过getBean拿到目标bean注入。
而真正的获取bean的逻辑,被封装到了一个TargetSource类的getTarget方法中,而这个TargetSource类最终被用来生成LazyProxy了,那么我们是不是可以推测,LazyProxy应该持有这个TargetSource对象。
而从我们懒加载的语意来讲,是说真正使用到这个bean(调用这个bean的某个方法时)的时候,才对这个属性进行注入/初始化。
那么对于当前这个例子来讲,就是说其实B创建的时候,并没有去调用getBean("a")去获取构造器的参数,而是直接生成了一个LazyProxy来做B构造器的参数,而B之后正真调用到A的方法时,才会去调用TargetSource中的getTarget获取A实例,即调用getBean("a"),这个时候A早就实例化好了,所以也就不会有循环依赖问题了。
❝某游戏大厂高级开发,专门和主管抬杠的小组长。想学dubbo的可以微信搜一搜「 「「稀饭下雪」」 」第一时间阅读Caffeine、dubbo等优秀框架的源码分析和教材讲解以及实际应用,有需要java面试资料的也可以关注一波,回复java资源获取我整理的专项资料。
❞
- 往期文章推荐 -
去年面了多个候选人,看看我挖的坑还有他们应该要补的Java基础(一)
去年面了多个候选人,看看我挖的坑还有他们应该要补的Java基础(二)
想学dubbo的看过来,2万字整理服务引入流程《一起玩dubbo系列第三篇》
- 学到东西了?点赞、分享、在看,拒绝白嫖 -