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

白昼怎懂夜的黑 提交于 2021-02-06 15:23:05

问题


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:

public class A {
    private B b;

    public B getB() {
        return b;
    }

    public void setB(B b) {
        this.b = b;
    }
}

public class B {
    private A a;

    public A getA() {
        return a;
    }

    public void setA(A a) {
        this.a = a;
    }
}

I've tried this(I've read that with @Bean annotation Spring won't invoke method every time bean is referenced, but in this case it's actually been invoked all the time):

@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;
    }
}

And this, with @Autowired of Configuration class fields:

@Configuration
public class Config {
    @Autowired
    A a;
    @Autowired
    B b;

    @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;
    }
}

Also I've tried all above with @Lazy annotation. Doesn't help. But works perfectly if I annotate setters of A and B with @Autowired. But it's not what I want right now. What am I doing wrong and is there any way to resolve Circular dependency in java config without usage of @Autowired?


回答1:


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;
}



回答2:


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.




回答3:


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.



来源:https://stackoverflow.com/questions/27622064/spring-resolve-circular-dependency-with-java-config-and-without-autowired

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!