Friday, April 1, 2022

Circular Dependency in Spring Framework

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 in Spring
Circular dependency

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

  1. Dependency Injection in Spring Framework
  2. Dependency Injection Using factory-method in Spring
  3. Wiring Collections in Spring
  4. How to Inject Null And Empty String Values in Spring
  5. Using util-namespace For Wiring Collection in Spring

You may also like-

  1. How to Inject Prototype Scoped Bean in Singleton Bean
  2. Using Spring Profiles to Switch Environment
  3. Spring NamedParameterJdbcTemplate Select Query Example
  4. How HashSet Works Internally in Java
  5. Heap Memory Allocation in Java
  6. Java Concurrency Interview Questions And Answers
  7. Array in Java With Examples
  8. HDFS High Availability