If you are predominantly using constructor injections then it is possible to create circular dependencies
in Spring.
What is a circular dependency
Circular dependency in Spring happens when two or more beans require instance of each other through constructor dependency injections.
For example: There is a ClassA that requires an instance of ClassB through constructor injection and ClassB requires an instance of class A through constructor injection. In that sort of configuration where beans for both classes need to be
injected into each other, Spring container can't decide which bean should be created first. The Spring IoC container will
detect this circular reference at runtime while trying to inject dependencies and throw a BeanCurrentlyInCreationException
.
Circular dependency example in Spring
Let’s see the same example as stated above. Here you will have a ClassA with dependency on ClassB and ClassB will have dependency on ClassA and that dependency is injected as a constructor injection.
In the example @ComponentScan is used to automatically discover beans.
ClassA.java
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class ClassA { private ClassB objB; @Autowired ClassA(ClassB objB){ this.objB = objB; } }
ClassB.java
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class ClassB { private ClassA objA; @Autowired ClassB(ClassA objA){ this.objA = objA; } }
Java class for Configuration
import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @ComponentScan(basePackages="org.netjs.exp.Spring_Example") public class AppConfig { }You can run this example code using the following Java code.
public class App { public static void main( String[] args ){ AbstractApplicationContext context = new AnnotationConfigApplicationContext (AppConfig.class); } }You will get the following exception-
Exception encountered during context initialization - cancelling refresh attempt org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'classA' defined in file Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'classB' defined in file Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'classA': Requested bean is currently in creation: Is there an unresolvable circular reference?
How to avoid circular dependency in Spring
1- In order to avoid circular dependency you can choose to configure the classes where such problem exists by using setter dependency injection.
Circular dependency example using setter injections
If we take the same example as above with few changes like in ClassA a displayMessage() method is added just for testing and ofcource wiring is configured to be done by setter injection.
ClassA.java
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class ClassA { private ClassB objB; /*@Autowired ClassA(ClassB objB){ this.objB = objB; }*/ public ClassB getObjB() { return objB; } @Autowired public void setObjB(ClassB objB) { this.objB = objB; } public void displayMessage(){ System.out.println("this is a test message"); } }
ClassB.java
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class ClassB { private ClassA objA; public ClassA getObjA() { return objA; } @Autowired public void setObjA(ClassA objA) { this.objA = objA; } }
Java class for Configuration
import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @ComponentScan(basePackages="org.netjs.exp.Spring_Example") public class AppConfig { }To run this code you can use the following Java class.
public class App { public static void main( String[] args ){ AbstractApplicationContext context = new AnnotationConfigApplicationContext (AppConfig.class); ClassA objA = (ClassA)context.getBean("classA"); objA.displayMessage(); context.close(); } }Now exception won’t be thrown and you will get output.
Output
this is a test message
With Setter injection Spring sets properties and resolves dependencies as late as possible, when the bean is actually created thus avoiding exception “BeanCurrentlyInCreationException”.
2- By default singleton beans are pre-instantiated. You can override this default behavior so that singleton beans will lazy-initialize, rather than be pre-instantiated. You just need to change it for one of the bean so that the bean configured to be lazy-initialize will not be instantiated at start up thus breaking the circular dependency.
Changed ClassA will look as following, notice the @Lazy annotation.import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; @Component public class ClassA { private ClassB objB; @Autowired @Lazy ClassA(ClassB objB){ this.objB = objB; } public ClassB getObjB() { return objB; } /*@Autowired public void setObjB(ClassB objB) { this.objB = objB; }*/ public void displayMessage(){ System.out.println("this is a test message"); } }
That's all for this topic Circular Dependency in Spring Framework. If you have any doubt or any suggestions to make please drop a comment. Thanks!
>>>Return to Spring Tutorial Page
Related Topics
You may also like-