The Spring reference manual explains how circular dependencies are resolved. The beans are instantiated first, then injected into each other.
Consider this class:
package mypackage;
public class A {
public A() {
System.out.println("Creating instance of A");
}
private B b;
public void setB(B b) {
System.out.println("Setting property b of A instance");
this.b = b;
}
}
And a similar class B:
package mypackage;
public class B {
public B() {
System.out.println("Creating instance of B");
}
private A a;
public void setA(A a) {
System.out.println("Setting property a of B instance");
this.a = a;
}
}
You can generally trust Spring to do
the right thing. It detects
configuration problems, such as
references to non-existent beans and
circular dependencies, at container
load-time. Spring sets properties and
resolves dependencies as late as
possible, when the bean is actually
created.
As the other answers have said, Spring just takes care of it, creating the beans and injecting them as required.
One of the consequences is that bean injection / property setting might occur in a different order to what your XML wiring files would seem to imply. So you need to be careful that your property setters don't do initialization that relies on other setters already having been called. The way to deal with this is to declare beans as implementing the InitializingBean interface. This requires you to implement the afterPropertiesSet() method, and this is where you do the critical initialization. (I would also include code to check that important properties have actually been set.)
The Spring container is able to resolve Setter-based circular dependencies but gives a runtime exception BeanCurrentlyInCreationException in case of Constructor-based circular dependencies.
In case of Setter-based circular dependency, the IOC container handles it differently from a typical scenario wherein it would fully configure the collaborating bean before injecting it.
For eg., if Bean A has a dependency on Bean B and Bean B on Bean C, the container fully initializes C before injecting it to B and once B is fully initialized it is injected to A. But in case of circular dependency, one of the beans is injected to the other before it is fully initialized.
In the codebase I'm working with (1 million + lines of code) we had a problem with long startup times, around 60 seconds. We were getting 12000+ FactoryBeanNotInitializedException.
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
where it does destroySingleton(beanName) I printed the exception with conditional breakpoint code:
If you generally use constructor-injection and don't want to switch to property-injection then Spring's lookup-method-injection will let one bean lazily lookup the other and hence workaround the cyclic dependency. See here: http://docs.spring.io/spring/docs/1.2.9/reference/beans.html#d0e1161
Say A depends on B, then Spring will first instantiate A, then B, then set properties for B, then set B into A.
But what if B also depends on A?
My understanding is: Spring just found that A has been constructed (constructor executed), but not fully initialized (not all injections done), well, it thought, it's OK, it's tolerable that A is not fully initialized, just set this not-fully-initialized A instances into B for now. After B is fully initialized, it was set into A, and finally, A was fully initiated now.
In other words, it just expose A to B in advance.
For dependencies via constructor, Sprint just throw BeanCurrentlyInCreationException, to resolve this exception, set lazy-init to true for the bean which depends on others via constructor-arg way.
If two beans are dependent on each other then we should not use Constructor injection in both the bean definitions. Instead we have to use setter injection in any one of the beans. (of course we can use setter injection n both the bean definitions, but constructor injections in both throw 'BeanCurrentlyInCreationException'
Class A {
private final B b; // must initialize in ctor/instance block
public A(B b) { this.b = b };
}
Class B {
private final A a; // must initialize in ctor/instance block
public B(A a) { this.a = a };
}
// Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'A': Requested bean is currently in creation: Is there an unresolvable circular reference?
Solution 1 ->
Class A {
private B b;
public A( ) { };
//getter-setter for B b
}
Class B {
private A a;
public B( ) { };
//getter-setter for A a
}
Solution 2 ->
Class A {
private final B b; // must initialize in ctor/instance block
public A(@Lazy B b) { this.b = b };
}
Class B {
private final A a; // must initialize in ctor/instance block
public B(A a) { this.a = a };
}
Constructor Injection fails when there is Circular Dependency between spring beans. So in this case we Setter injection helps to resolve the issue.
Basically, Constructor Injection is useful for Mandatory dependencies, for optional dependencies better to use Setter injection because we can do re-injection.