Spring. Resolve circular dependency with java config and without @Autowired

后端 未结 3 738
一生所求
一生所求 2021-02-13 12:25

I\'ve got circular dependency and java config. While resolving it with xml config is very easy I can\'t resolve it with java config without @Autowired. Beans:

pu         


        
相关标签:
3条回答
  • 2021-02-13 12:32

    The behavior you want to get is the following

    A a = new A();
    B b = new B();
    a.setB(b);
    b.setA(a);
    

    @Bean methods don't give you that. They run to completion to provide a bean instance.

    You basically have to partially create one of the instances, then finish initializing it when you've created the other.

    @Configuration
    class Config {
        @Bean
        public A a() {
            A a = new A();
            return a;
        }
    
        @Bean
        public B b() {
            B b = new B();
            A a = a();
            b.setA(a);
            a.setB(b);
            return b;
        }
    }
    

    or

    @Bean
    public B b(A a) {
        B b = new B();
        b.setA(a);
        a.setB(b);
        return b;
    }
    
    0 讨论(0)
  • 2021-02-13 12:50

    I want to add another possible solution for your code. Instead of setting circular dependencies right in the config:

    @Configuration
    public class Config {
        @Bean
        public A a() {
            A a = new A();
            a.setB(b());
            return a;
        }
    
        @Bean
        public B b() {
            B b = new B();
            b.setA(a());
            return b;
        }
    }
    

    You could also let the spring do the work with the power of @Autowired annotation.

    @Configuration
    public class Config {
        @Bean
        public A a() {
            A a = new A();
            return a;
        }
    
        @Bean
        public B b() {
            B b = new B();
            return b;
        }
    }
    
    public class A {
        private B b;
    
        @Autowired
        public setB(B b) { this.b = b; }
    }
    
    public class B {
        private A a;
    
        @Autowired
        public setA(A a) { this.a = a; }
    }
    

    Of course it is non trivial from the "clean/readable/understandable" point of view because now your configuration is mixed in @Configuration and class itself. But as circular dependencies are quite rare, we could afford the hack.

    0 讨论(0)
  • 2021-02-13 12:58

    Another approach using @Autowired and @Component is to use this pattern:

    @Component
    class A {
        private B b;
    
        public B getB() {
            return b;
        }
    
        public void setB(final B b) {
            this.b = b;
        }
    }
    
    
    @Component
    class B {
        private final A a;
    
        @Autowired
        public B(final A a) {
            this.a = a;
            a.setB(this);
        }
    
        public A getA() {
            return a;
        }
    }
    

    This eliminates the need for a separate @Configuration-class. Furthermore, the setB-method can possibly be package-protected if the classes exist in the same package to minimize scoping as much as possible.

    0 讨论(0)
提交回复
热议问题