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