高级开发竟然被构造器循环依赖难住了?
2023-03-09 22:04:32 时间
是这样的,有个实习生朋友问了我循环依赖的问题,我将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这个大杀器...只需要我们对刚刚那两个类小小的改造一下:
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早就实例化好了,所以也就不会有循环依赖问题了。
相关文章
- 在 Go 里用 CGO?这 7 个问题你要关注!
- 9款优秀的去中心化通讯软件 Matrix 的客户端
- 求职数据分析,项目经验该怎么写
- 在OKR中,我看到了数据驱动业务的未来
- 火山引擎云原生大数据在金融行业的实践
- OpenHarmony富设备移植指南(二)—从postmarketOS获取移植资源
- 《数据成熟度指数》报告:64%的企业领袖认为大多数员工“不懂数据”
- OpenHarmony 小型系统兼容性测试指南
- 肯睿中国(Cloudera):2023年企业数字战略三大趋势预测
- 适用于 Linux 的十大命令行游戏
- GNOME 截图工具的新旧截图方式
- System76 即将推出的 COSMIC 桌面正在酝酿大变化
- 2GB 内存 8GB 存储即可流畅运行,Windows 11 极致精简版系统 Tiny11 发布
- 迎接 ecode:一个即将推出的具有全新图形用户界面框架的现代、轻量级代码编辑器
- loongarch架构介绍(三)—地址翻译
- Go 语言怎么解决编译器错误“err is shadowed during return”?
- 敏捷:可能被开发人员遗忘的部分
- Denodo预测2023年数据管理和分析的未来
- 利用数据推动可持续发展
- 在 Vue3 中实现 React 原生 Hooks(useState、useEffect),深入理解 React Hooks 的