zoukankan      html  css  js  c++  java
  • 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;
     
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    public class ClassB {
     
    @Autowired
     
    ClassA classA
     
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    解决办法:

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

    (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>   
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

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

    @Autowired     
     
    @Lazy      
     
    private ClassA classA; 
     
     
    @Autowired 
     
    @Lazy      
     
    private ClassB classB; 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    构造器注入循环依赖实例

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

    @Component
    public class CircularDependencyA {
     
        private CircularDependencyB circB;
     
        @Autowired
        public CircularDependencyA(CircularDependencyB circB) {
            this.circB = circB;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    @Component
    public class CircularDependencyB {
     
        private CircularDependencyA circA;
     
        @Autowired
        public CircularDependencyB(CircularDependencyA circA) {
            this.circA = circA;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    @Configuration
    @ComponentScan(basePackages = { "com.baeldung.circulardependency" })
    public class TestConfig {
    }
    
    • 1
    • 2
    • 3
    • 4
    @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
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    运行方法
    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

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

    @Component
    public class CircularDependencyA {
     
        private CircularDependencyB circB;
     
        @Autowired
        public CircularDependencyA(@Lazy CircularDependencyB circB) {
            this.circB = circB;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

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

    @Component
    public class CircularDependencyA {
     
        private CircularDependencyB circB;
     
        @Autowired
        public void setCircB(CircularDependencyB circB) {
            this.circB = circB;
        }
     
        public CircularDependencyB getCircB() {
            return circB;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    @Component
    public class CircularDependencyB {
     
        private CircularDependencyA circA;
     
        private String message = "Hi!";
     
        @Autowired
        public void setCircA(CircularDependencyA circA) {
            this.circA = circA;
        }
     
        public String getMessage() {
            return message;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    @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());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    (4) 使用@PostConstruct

    @Component
    public class CircularDependencyA {
     
        @Autowired
        private CircularDependencyB circB;
     
        @PostConstruct
        public void init() {
            circB.setCircA(this);
        }
     
        public CircularDependencyB getCircB() {
            return circB;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    @Component
    public class CircularDependencyB {
     
        private CircularDependencyA circA;
         
        private String message = "Hi!";
     
        public void setCircA(CircularDependencyA circA) {
            this.circA = circA;
        }
         
        public String getMessage() {
            return message;
        }
     
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    (5)实现ApplicationContextAware与InitializingBean

    @Component
    public 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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    @Component
    public class CircularDependencyB {
     
        private CircularDependencyA circA;
     
        private String message = "Hi!";
     
        @Autowired
        public void setCircA(CircularDependencyA circA) {
            this.circA = circA;
        }
     
        public String getMessage() {
            return message;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
  • 相关阅读:
    《算法竞赛入门经典》(刘汝佳)——排序与检索(基础)
    Python中的GIL
    MongoDB 安装
    python3 报错集合
    socket 实例化方法
    socket入门
    Day_6作业_模拟人生
    高阶函数举例
    面向对象_python
    xml
  • 原文地址:https://www.cnblogs.com/suizhikuo/p/13787600.html
Copyright © 2011-2022 走看看