点击链接阅读原文,获取更多技术内容:本篇不仅仅是介绍Spring循环依赖的原理,而且给出Spring不能支持的循
点击链接阅读原文,获取更多技术内容:
本篇不仅仅是介绍Spring循环依赖的原理,而且给出Spring不能支持的循环依赖场景与案例,对其进行详细解析,同时给出解决建议与方案,以后出现此问题可以少走弯路。
作者 | 刘斌(蔆素)
(资料图片)
来源 | 阿里开发者公众号
背景
1、循环依赖异常信息
应用时间时间久 应用多人同时并行开发 应用保证迭代进度经常出现启动时出现循环依赖异常
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name "taskPunchEvent": Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name "playContentService": Bean with name "playContentService" has been injected into other beans [toVoConvertor] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using "getBeanNamesOfType" with the "allowEagerInit" flag turned off, for example. at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessProperties(CommonAnnotationBeanPostProcessor.java:325) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1404) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:592) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:277) at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1255) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1175) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:595) ... 40 moreCaused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name "playContentService": Bean with name "playContentService" has been injected into other beans [toVoConvertor] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using "getBeanNamesOfType" with the "allowEagerInit" flag turned off, for example. at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:622) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.resolveBeanByName(AbstractAutowireCapableBeanFactory.java:452) at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.autowireResource(CommonAnnotationBeanPostProcessor.java:527) at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.getResource(CommonAnnotationBeanPostProcessor.java:497) at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor$ResourceElement.getResourceToInject(CommonAnnotationBeanPostProcessor.java:637) at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:180) at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:90) at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessProperties(CommonAnnotationBeanPostProcessor.java:322) ... 51 more
2、依赖关系
先不关注其他不规范问题,看现象
3、涉及基础知识
Spring bean 创建流程 Dynamic Proxy 动态代理 Spring-AOP 原理问题
1、什么是循环依赖?
2、为什么会产生循环依赖?
3、循环依赖有哪些场景?
4、Spring如何解决循环依赖的?
5、Spring为什么使用三级缓存?
6、Spring支持AOP循环依赖,为何还存在循环依赖异常?
7、Spring不支持的循环依赖场景及如何解决?
注:Spring启动流程与Bean创建初始化流程如不熟悉,自行补习,篇幅原因此处不做介绍
Spring循环依赖
1、什么是循环依赖
2、核心概念
BeanDefinition:spring核心bean的配置信息 Spring Bean:spring管理的已经初始化好以后的可使用的实例 首先,通过spring通过扫描各种注解 @Compoent、@Service、@Configuration等等把需要交给spring管理的bean初始化成 BeanDefinition 的列表 然后,根据 BeanDefinition 创建spring bean的实例 Java Bean:Java简单通过构造函数创建的对象 Spring通过推断构造方法后,通过反射调用构造函数创建的对象1、什么情况下出现循环依赖
并非使用者手动去getBean才会加载并初始化,而是框架启动时进行加载
Spring创建Bean - #DefaultListableBeanFactory#preInstantiateSingletons@Overridepublic void preInstantiateSingletons() throws BeansException { //...... ListbeanNames = new ArrayList<>(this.beanDefinitionNames); // Trigger initialization of all non-lazy singleton beans... for (String beanName : beanNames) { RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { if (isFactoryBean(beanName)) { //FactoryBean接口处理 ...... } else { //正常Bean的加载入口 getBean(beanName); } } } //......}
4、循环依赖场景
构造器内的循环依赖 注入的好处很明显,如果容器中不存在或者存在多个实现时,可以从容处理。 强依赖,先有鸡还是先有蛋问题暂无解,此依赖方式Spring不支持,除非自身实现代理加延迟注入,这种方式很难解决,除非实现类似于lazy生成代理方式进行解耦来实现注入,Spring没有支持可能因为此种注入场景都可以用其他方式代替且场景极少。 弱依赖,spring 4.3之后增加 ObjectProvider 来处理阿里云开发者社区,千万开发者的选择。百万精品技术内容、千节免费系统课程、丰富的体验场景、活跃的社群活动、行业专家分享交流,尽在: