高级开发竟然被构造器循环依赖难住了?

是这样的,有个实习生朋友问了我循环依赖的问题,我将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这个大杀器...只需要我们对刚刚那两个类小小的改造一下:

image-20210627112311932

lazy为啥可以解决这个问题?

反调@Lazy注解可以看到

image-20210627112544024

从源码我们可以看到,对于@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基础(二)


肥肥的主管和帅气的小饭饭讨论了下ForkJoinPool


想学dubbo的看过来,2万字整理服务引入流程《一起玩dubbo系列第三篇》


一起玩dubbo,万字长文揭秘服务暴露


一起玩dubbo,先入个门


- 学到东西了?点赞、分享、在看,拒绝白嫖 -

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值