spring中的循环依赖问题
spring应用中,默认是有循环依赖的控制,
场景:
ServiceA、ServiceB、ServieC 多个bean互相依赖,形成闭环。
spring默认使用三级缓存控制循环依赖的问题,但是前提是:
bean不是以构造方法注入,单例bean(多例bean不被spring管理,只管创建)。
spring3级缓存解决循环依赖:
spring构建ServiceA时,发现依赖于ServiceB,
于是先去构造ServiceB的bean,先使用构造方法实例化了一个ServiceA,然后将这个ServiceA放入三级缓存singletonFactories中,接着将这个ServiceA注入到ServiceB中完成ServiceB的创建,将ServiceB放入单例池(singletonObjects,一个ConcurrentHashMap)中,将ServiceA放入二级缓存earlySingletonObjects,最后将单例池中的ServiceB注入到ServiceA中,完成ServiceA的完全创建,放入单例池中。
其中的一个Service使用了@Async注解后:
Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'projectTaskService': Bean with name 'projectTaskService' has been injected into other beans [projectTaskReplyService,materialPlanService] 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:624)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:207)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.resolveBeanByName(AbstractAutowireCapableBeanFactory.java:454)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.autowireResource(CommonAnnotationBeanPostProcessor.java:543)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.getResource(CommonAnnotationBeanPostProcessor.java:513)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor$ResourceElement.getResourceToInject(CommonAnnotationBeanPostProcessor.java:653)
at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:224)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:116)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessProperties(CommonAnnotationBeanPostProcessor.java:334)
... 31 common frames omitted
Disconnected from the target VM, address: '127.0.0.1:56144', transport: 'socket'
使用异步注解的时候,spring的默认实现是生成该类的代理对象,通过代理对象调用异步方法,而现在就造成了该类有了两个代理对象,一个先前已经被注入到了别的bean里去了,一个刚生成的,这就造成了同一类有了不同得两个代理,而spring对bean的属性注入只允许最终代理进行注入,也就是要都以最后一个为准,而先前就已经注入了一个旧的代理,这就造成了错误。