这个其实是一个特别高频的面试题,松哥也一直很想和大家仔细来聊一聊这个话题,网上关于这块的文章很多,但是我一直觉得要把这个问题讲清楚还有点难度,今天我来试一试,看能不能和小伙伴们把这个问题梳理清楚,当然,如果小伙伴们觉得看文章不过瘾,松哥也有 Spring 源码分析的视频教程,戳这里:最新版 Spring 源码视频教程

一 循环依赖

1.1 什么是循环依赖

首先,什么是循环依赖?这个其实好理解,就是两个 Bean 互相依赖,类似下面这样:

privateObjectbuildLazyResolutionProxy(finalDependencyDescriptordescriptor,final@NullableStringbeanName,booleanclassOnly){BeanFactorybeanFactory=getBeanFactory();finalDefaultListableBeanFactorydlbf=(DefaultListableBeanFactory)beanFactory;TargetSourcets=newTargetSource(){@OverridepublicClass<?>getTargetClass(){returndescriptor.getDependencyType();}@OverridepublicbooleanisStatic(){returnfalse;}@OverridepublicObjectgetTarget(){Set<String>autowiredBeanNames=(beanName!=null?newLinkedHashSet<>(1):null);Objecttarget=dlbf.doResolveDependency(descriptor,beanName,autowiredBeanNames,null);if(target==null){Class<?>type=getTargetClass();if(Map.class==type){returnCollections.emptyMap();}elseif(List.class==type){returnCollections.emptyList();}elseif(Set.class==type||Collection.class==type){returnCollections.emptySet();}thrownewNoSuchBeanDefinitionException(descriptor.getResolvableType(),"Optionaldependencynotpresentforlazyinjectionpoint");}if(autowiredBeanNames!=null){for(StringautowiredBeanName:autowiredBeanNames){if(dlbf.containsBean(autowiredBeanName)){dlbf.registerDependentBean(autowiredBeanName,beanName);}}}returntarget;}@OverridepublicvoidreleaseTarget(Objecttarget){}};ProxyFactorypf=newProxyFactory();pf.setTargetSource(ts);Class<?>dependencyType=descriptor.getDependencyType();if(dependencyType.isInterface()){pf.addInterface(dependencyType);}ClassLoaderclassLoader=dlbf.getBeanClassLoader();return(classOnly?pf.getProxyClass(classLoader):pf.getProxy(classLoader));}

这个方法就是用来生成代理的对象的,这里构建了代理对象 TargetSource,在其 getTarget 方法中,会去执行 doResolveDependency 获取到被代理的对象(doResolveDependency 的获取逻辑可以参考 最新版 Spring 源码视频教程),而 getTarget 方法只有在需要的时候才会被调用。所以,@Lazy 注解所做的事情,就是在给 Bean 中的各个属性注入值的时候,原本需要去 Spring 容器中找注入的对象,现在不找了,先给一个代理对象顶着,需要的时候再去 Spring 容器中查找。

后续的逻辑我就不再多说了,小伙伴们参考最新版 Spring 源码视频教程即可。

好啦,现在小伙伴们明白了 @Lazy 注解是如何解决 Spring 循环依赖了吧~

虽然解决了,但是我们在日常开发中,要是能避免循环依赖还是要去避免~

本篇文章来源于微信公众号: 江南一点雨



微信扫描下方的二维码阅读本文

此作者没有提供个人介绍
最后更新于 2024-08-01