Open In App

Circular Dependencies in Spring

Last Updated : 15 Nov, 2022
Improve
Improve
Like Article
Like
Save
Share
Report

In this article, we will discuss one of the most important concepts of Spring i.e. Circular dependency. Here we will understand what is circular dependency in Spring and how we can resolve circular dependency issues in Spring.

What is Circular Dependency?

In software engineering, a circular dependency is a relation between two or more modules that either directly or indirectly depend on each other to function properly. Let’s try to understand this definition by rolling it with Spring. Suppose, There is a bean A depends on another bean B, and the bean B depends on bean A as well just like below:

Bean A → Bean B → Bean A

So, This is all about definition and we also understood what is circular dependency. But you all must be thinking that how it can cause issues in spring. Let’s understand. Whenever Spring context creates beans by reading the configuration file i.e. meta-data. It tries to create beans in the order needed for them to work completely. Let’s take an example to understand this

Bean A → Bean B → Bean C

Here as you guys can see, Bean A needs Bean B and Bean B needs Bean C. So here Spring will create bean C, then create bean B (and inject bean C into it), then create bean A (and inject bean B into it). But as we discussed earlier, Suppose, There is a bean A that depends on another bean B, and the bean B depends on bean A as well just like below.

Bean A → Bean B → Bean A

Here as you can see, there is a circular dependency and Spring won’t be able to decide which of the beans should be created first, since they depend on one another. When Spring encountered this type of issue, it raise an exception BeanCurrentlyInCreationException while loading context.

Note: We have to remember this one thing that spring context throw BeanCurrentlyInCreationException while loading context when we use constructor-based dependency injection. If we use any other dependency injection method then spring will not throw this exception in case of circular dependency.

Now we have understood the circular dependency and the issue with circular dependency in Spring. So let’s understand this by doing a little code now. Let’s define two beans that depend on one another (via constructor injection):

Java




package com.gfg.technicalscripter;
  
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
  
@Component
public class BeanA {
  
    private BeanB beanB;
  
    @Autowired
    public BeanA(BeanB beanB) {
        this.beanB = beanB;
    }
}


Java




package com.gfg.technicalscripter;
  
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
  
@Component
public class BeanB {
  
    private BeanA beanA;
  
    @Autowired
    public BeanB(BeanA beanA) {
        this.beanA = beanA;
    }
}


Java




package com.gfg.technicalscripter;
  
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
  
@Configuration
@ComponentScan(basePackages = { "com.gfg.technicalscripter" })
public class AppConfig {
  
}


Java




package com.gfg.technicalscripter;
  
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
  
public class App {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
    }
}


If we try to run this test, we will get this exception: BeanCurrentlyInCreationException: Error creating bean with name ‘beanA’: Requested bean is currently in creation: Is there an unresolvable circular reference?

The Workarounds: Now we faced the issue and every one of you will be thinking that how we can resolve the issue. We’ll now try some of the most popular ways to deal with this problem.

  • Use @Lazy: We are assuming that you know about @Lazy annotation and how it works. So with the help of @Lazy annotation, we can solve the issue. We can tell Spring to initialize one of the beans lazily. The injected bean will only be fully created when it’s first needed and at the time of bean creation, it injects the proxy bean as a dependency.

Java




package com.gfg.technicalscripter;
  
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
  
@Component
public class BeanA {
  
    private BeanB beanB;
  
    @Autowired
    public BeanA(@Lazy BeanB beanB) {
        this.beanB = beanB;
    }
}


Now when we run the project and Spring will load the context then it won’t throw BeanCurrentlyInCreationException.

  • Use Setter/Field Injection: Instead of going for constructor-based dependency injection in the context of circular dependency, we should go for Setter-based dependency injection as suggested by Spring documentation. This way, Spring creates the beans, but the dependencies are not injected until they are needed.

Java




package com.gfg.technicalscripter;
  
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
  
@Component
public class BeanA {
  
    BeanA() {
        System.out.println("BeanA constructor called !!!");
    }
  
    private BeanB beanB;
  
    @Autowired
    public void setBeanB(BeanB beanB) {
        System.out.println("Setting property beanB of BeanA instance");
        this.beanB = beanB;
    }
}


Java




package com.gfg.technicalscripter;
  
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
  
@Component
public class BeanB {
  
    BeanB() {
        System.out.println("BeanB constructor called !!!");
    }
  
    private BeanA beanA;
  
    @Autowired
    public void setBeanA(BeanA beanA) {
        System.out.println("Setting property beanA of BeanB instance");
        this.beanA = beanA;
    }
}


In the case of setter-based dependency injection, Spring creates a bean by calling the constructor first and then injecting the dependencies with the help of setter methods. So here Spring won’t raise BeanCurrentlyInCreationException as Spring will have the required object at the time of dependency injection. There are many ways to deal with circular dependencies in Spring. The recommended method of solving the circular dependency issues is using setter injections. But there are other alternatives too, which restrict Spring to fully initializing beans with dependency at once using different strategies.



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads