Spring循环依赖报错Bean with name '**' has been injected into other beans [**] in its raw version as part

异常详情

Bean with name ‘commonService’ has been injected into other beans [] 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.**

springboot循环依赖解决

1. 循环依赖是什么?

Bean A 依赖 B,Bean B 依赖 A这种情况下出现循环依赖。
Bean A → Bean B → Bean A
更复杂的间接依赖造成的循环依赖如下。
Bean A → Bean B → Bean C → Bean D → Bean E → Bean A

2. 循环依赖会产生什么结果?

当Spring正在加载所有Bean时,Spring尝试以能正常创建Bean的顺序去创建Bean。
例如,有如下依赖:
Bean A → Bean B → Bean C
Spring先创建beanC,接着创建bean B(将C注入B中),最后创建bean A(将B注入A中)。

但当存在循环依赖时,Spring将无法决定先创建哪个bean。这种情况下,Spring将产生异常BeanCurrentlyInCreationException。

3.普通注入之间的循环依赖

比如:我现在有一个ServiceA需要调用ServiceB的方法,那么ServiceA就依赖于ServiceB,那在ServiceB中再调用ServiceA的方法,就形成了循环依赖。Spring在初始化bean的时候就不知道先初始化哪个,bean就会报错。

public class ClassA { 
   @Autowired
   ClassB classB; 
}
public class ClassB { 
    @Autowired 
    ClassA classA 
}

解决办法:

如何解决循环依赖,最好的方法是重构代码,进行解耦,如果没有时间重构,可以使用下面的方法:

(1)在你的配置文件中,在互相依赖的两个bean的任意一个加上lazy-init属性

<bean id="ServiceDependent1" class="org.xyz.ServiceDependent1" lazy-init="true">
<constructor-arg ref="Service"/>
</bean>
<bean id="ServiceDependent2" class="org.xyz.ServiceDependent2" lazy-init="true">
<constructor-arg ref="Service"/>
</bean>   

(2)在你注入bean时,在互相依赖的两个bean上加上@Lazy注解也可以

    @Autowired
    @Lazy
    private ClassA classA;
    @Autowired
    @Lazy
    private ClassB classB;

构造器注入循环依赖实例

首先定义两个相互通过构造器注入依赖的bean。

复制代码
@Componentpublic
    class CircularDependencyA {
        private CircularDependencyB circB;

        @Autowired
        public CircularDependencyA(CircularDependencyB circB) {
            this.circB = circB;
        }
    }
复制代码
复制代码
    @Componentpublic
    class CircularDependencyB {
        private CircularDependencyA circA;

        @Autowired
        public CircularDependencyB(CircularDependencyA circA) {
            this.circA = circA;
        }
    }
复制代码
    @Configuration
    @ComponentScan(basePackages = {"com.baeldung.circulardependency"})
    public class TestConfig {
    }
@RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = {TestConfig.class})
    public class CircularDependencyTest {
        @Test
        public void givenCircularDependency_whenConstructorInjection_thenItFails() {               
           // Empty test; we just want the context to load
    }
}

运行方法
givenCircularDependency_whenConstructorInjection_thenItFails
将会产生异常:BeanCurrentlyInCreationException: Error creating bean with name ‘circularDependencyA’:
Requested bean is currently in creation: Is there an unresolvable circular reference?

如何解决

(1)重新设计

重新设计结构,消除循环依赖。

(2)使用注解 @Lazy

一种最简单的消除循环依赖的方式是通过延迟加载。在注入依赖时,先注入代理对象,当首次使用时再创建对象完成注入。

复制代码
    @Componentpublic
    class CircularDependencyA {
        private CircularDependencyB circB;

        @Autowired
        public CircularDependencyA(@Lazy CircularDependencyB circB) {
            this.circB = circB;
        }
    }
复制代码

使用@Lazy后,运行代码,可以看到异常消除。
(3)使用Setter/Field注入
Spring文档建议的一种方式是使用setter注入。当依赖最终被使用时才进行注入。对前文的样例代码少做修改,来观察测试效果。

复制代码
    @Componentpublic
    class CircularDependencyA {
        private CircularDependencyB circB;

        @Autowired
        public void setCircB(CircularDependencyB circB) {
            this.circB = circB;
        }

        public CircularDependencyB getCircB() {
            return circB;
        }
    }
复制代码
复制代码
    @Componentpublic
    class CircularDependencyB {
        private CircularDependencyA circA;
        private String message = "Hi!";

        @Autowired
        public void setCircA(CircularDependencyA circA) {
            this.circA = circA;
        }

        public String getMessage() {
            return message;
        }
    }
复制代码
复制代码
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = {TestConfig.class})
    public class CircularDependencyTest {
        @Autowired
        ApplicationContext context;

        @Bean
        public CircularDependencyA getCircularDependencyA() {
            return new CircularDependencyA();
        }

        @Bean
        public CircularDependencyB getCircularDependencyB() {
            return new CircularDependencyB();
        }

        @Test
        public void givenCircularDependency_whenSetterInjection_thenItWorks() {
            CircularDependencyA circA = context.getBean(CircularDependencyA.class);
            Assert.assertEquals("Hi!", circA.getCircB().getMessage());
        }
    }
复制代码

(4) 使用@PostConstruct

复制代码
    @Componentpublic
    class CircularDependencyA {
        @Autowired
        private CircularDependencyB circB;

        @PostConstruct
        public void init() {
            circB.setCircA(this);
        }

        public CircularDependencyB getCircB() {
            return circB;
        }
    }
复制代码
复制代码
    @Componentpublic
    class CircularDependencyB {
        private CircularDependencyA circA;
        private String message = "Hi!";

        public void setCircA(CircularDependencyA circA) {
            this.circA = circA;
        }

        public String getMessage() {
            return message;
        }
    }
复制代码

(5)实现ApplicationContextAware与InitializingBean

复制代码
    @Componentpublic
    class CircularDependencyA implements ApplicationContextAware, InitializingBean {
        private CircularDependencyB circB;
        private ApplicationContext context;

        public CircularDependencyB getCircB() {
            return circB;
        }

        @Override
        public void afterPropertiesSet() throws Exception {
            circB = context.getBean(CircularDependencyB.class);
        }

        @Override
        public void setApplicationContext(final ApplicationContext ctx) throws BeansException {
            context = ctx;
        }
    }
复制代码
复制代码
    @Componentpublic
    class CircularDependencyB {
        private CircularDependencyA circA;
        private String message = "Hi!";

        @Autowired
        public void setCircA(CircularDependencyA circA) {
            this.circA = circA;
        }

        public String getMessage() {
            return message;
        }
    }
复制代码

 

posted @   Boblim  阅读(2769)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
· 零经验选手,Compose 一天开发一款小游戏!
历史上的今天:
2017-03-08 mysql sql中的一些问题,Null与空字符
2017-03-08 C语言宏定义和宏定义函数
点击右上角即可分享
微信分享提示