Spring循環依賴 This is often the result of over-eager type matching - consider using 'getBeanNamesOfT...

結論:當A、B對象之間相互依賴,A早於B實例化,並且A對象使用了@Async註解或由BeanPostProcessor後置處理器返回了代理對象時,會產生以下報錯:

org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'a': Bean with name 'a' has been injected into other beans [b] 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:585) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543) at org.springframework.context.annotation.AnnotationConfigApplicationContext.<init>(AnnotationConfigApplicationContext.java:84)

在springboot中,以上報錯被捕捉,拋出的異常是:

The dependencies of some of the beans in the application context form a cycle


原因:我們知道,spring三級緩存一定程度上解決了循環依賴問題。A對象在實例化之後,屬性賦值【opulateBean(beanName, mbd, instanceWrapper)】執行之前,將ObjectFactory添加至三級緩存中,從而使得在B對象實例化後的屬性賦值過程中,能從三級緩存拿到ObjectFactory,調用getObject()方法拿到A的引用,B由此能順利完成初始化並加入到IOC容器。此時A對象完成屬性賦值之後,將會執行初始化【initializeBean(beanName, exposedObject, mbd)方法】,重點是@Async註解的處理正是在這地方完成的,其對應的後置處理器AsyncAnnotationBeanPostProcessor,在postProcessAfterInitialization方法中將返回代理對象,此代理對象與B中持有的A對象引用不同,導致了以上報錯。


有以下解決辦法:

    1)在A類上加@Lazy,保證A對象實例化晚於B對象;

    2)在A類上使用@DependsOn註解,保證A對象實例化晚於B對象(注意如果AB兩個類相互DependsOn,也會形成循環依賴)

    3)設置 AbstractAutowireCapableBeanFactory.setAllowRawInjectionDespiteWrapping(true),不會報錯但會導致B持有的A引用不是最終的代理對象;

    4)不使用@Async註解,通過自定義異步工具類發起異步線程;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章