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?
A simple way to break the cycle is by telling Spring to initialize one of the beans lazily. So, instead of fully initializing the bean, it will create a proxy to inject it into the other bean. The injected bean will only be fully created when it's first needed.
To resolve the circular dependency, you must break the loop by replacing the dynamic reference to the bucket resource.
Circular dependency problem can be overcome by using interfaces or events. So for the above problem, we can introduce an interface in between the “ MiddleTier ” and “ Dal ”. This interface project you will implement in the middle layer project on the “ Customer ” class.
To reduce or eliminate circular dependencies, architects must implement loose component coupling and isolate failures. One approach is to use abstraction to break the dependency chain. To do this, you introduce an abstracted service interface that delivers underlying functionality without direct component coupling.
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;
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With