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

开发 前端
是这样的,有个实习生朋友问了我循环依赖的问题,我将Spring内部的三级缓存原理都跟他说了,并保证Spring已经解决了这个问题,然后他扔了一道题给我,说报错了。

[[407544]]

是这样的,有个实习生朋友问了我循环依赖的问题,我将Spring内部的三级缓存原理都跟他说了,并保证Spring已经解决了这个问题,然后他扔了一道题给我,说报错了。

好家伙,感情是想我让我查bug

你们看看?

  1. @Component 
  2. public class A { 
  3.  
  4.     private final B b; 
  5.  
  6.     public A(final B b) { 
  7.         this.b = b; 
  8.     } 
  9.  
  10.     public void print() { 
  11.         System.out.println("in a"); 
  12.     } 
  1. @Component 
  2. public class B { 
  3.  
  4.     private final A a; 
  5.  
  6.     public B(final A a) { 
  7.         this.a = a; 
  8.     } 
  9.  
  10.     public void print() { 
  11.         System.out.println("in b"); 
  12.     } 
  1. 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? 
  2.  at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:800) 
  3.  at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:229) 
  4.  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1354) 
  5.  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1204) 
  6.  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:564) 
  7.  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524) 
  8.  at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) 
  9.  at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) 
  10.  at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) 
  11.  at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) 
  12.  at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:944) 
  13.  at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918) 
  14.  at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583) 
  15.  at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:782) 
  16.  at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:774) 
  17.  at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:439) 
  18.  at org.springframework.boot.SpringApplication.run(SpringApplication.java:339) 
  19.  at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:123) 
  20.  at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:99) 
  21.  at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124) 
  22.  ... 68 more 
  23. 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这个大杀器...只需要我们对刚刚那两个类小小的改造一下:

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

反调@Lazy注解可以看到

从源码我们可以看到,对于@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早就实例化好了,所以也就不会有循环依赖问题了。

责任编辑:武晓燕 来源: 稀饭下雪
相关推荐

2023-02-17 07:27:28

2021-06-11 06:38:25

CTO浏览器文件

2021-07-07 11:15:05

文件前端浏览器

2021-01-07 08:23:02

日志

2012-03-13 11:21:34

索尼AndroidVita OS

2023-11-22 09:30:50

e签宝面试企业面经

2023-12-14 12:56:00

链式调用代码

2020-08-11 10:20:26

http数据库状态

2017-12-07 08:56:21

2020-04-30 10:24:35

Spring循环依赖Java

2024-11-07 08:28:53

2009-07-21 12:35:00

Scala从构造器

2023-05-04 08:06:27

Spring循环依赖

2022-08-18 08:41:32

RPC微服务事件驱动

2024-07-29 07:02:00

OpenAIGPT-4oAI

2012-02-03 09:25:39

Node.js

2023-01-12 16:57:39

ChatGPT

2021-05-10 11:04:46

Windows 操作系统微软

2021-02-02 18:03:00

字符串面试官子序列

2021-09-01 11:45:10

Spring循环依赖面试
点赞
收藏

51CTO技术栈公众号