问题
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