Unresolved circular dependency in spring dependency injection

Upasana | September 30, 2020 | 3 min read | 1,690 views


What is Circular Dependency in Spring?

When class A requires an instance of class B through constructor/setter injection, and class B requires an instance of class A through constructor/setter injection and you configure beans for classes A and B to be injected into each other, the Spring IoC container detects this circular reference at runtime, and throws a BeanCurrentlyInCreationException.

A circular dependency between bean A and bean B forces one of the beans to be injected into the other prior to being fully initialized itself (a classic chicken/egg scenario).

Circular Dependncy - A Symptom of Bad Design

Circular dependencies are usually a symptom of bad design!

This is most likely a design level problem and should be resolved by modifying the object level design. This problem indicates that two different Classes share the common responsibility and your design is lacking the abstraction of responsibilities.

Example Code for Circular Dependency

Bean1 java source
@Component("bean1")
public class Bean1 {

    @Autowired
    private Bean2 bean2;   (1)
}

@Component("bean1")
public class Bean2 {

    @Autowired
    private Bean1 bean1; (2)
}
1 Bean1 is dependent on Bean2
2 Bean2 is dependent on Bean1

The kind of error thrown by Spring Container looks like this:

Bean with name 'bean1' has been injected into other beans [bean2] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.

Possible Solutions

1. Refactor the design to remove circular dependency

Refactoring the design is the only elegant way of breaking this circular dependency, only a cleaner design with orthogonal responsibilities can solve the problem in its entirty.

2. Use @Lazy autowiring

This is one of the simplest workaround where we break the circular dependency by delaying the injection using @Lazy annotation in one of the beans. This way the injected bean will only be created when it is first needed.

The code will look like this:

Using Lazy autowiring
@Component
public class Bean1 {

    private Bean2 bean2;

    @Autowired
    public Bean1(@Lazy Bean2 bean2) {
        this.bean2 = bean2;
    }
}

or this:

@Component
public class Bean1 {

    @Lazy
    @Autowired
    private Bean2 bean2;
}

3. Use Setter Injection instead of constructor injection

Other possible solution is to edit the source code of some classes to be configured by setters rather than constructors. Alternatively, avoid constructor injection and use setter injection only. In other words, although it is not recommended, you can configure circular dependencies with setter injection. This may work for few specific scenario’s but its still a workaround.

4. Use PostConstruct to set one way dependency

Third option is to specify one way dependency through Injection using @Autowired and other way dependency via invoking setter manually from PostConstruct method of first bean.

Use PostConstruct to set one way dependency
@Component("bean1")
public class Bean1 {

    @Autowired
    private Bean2 bean2;

    @PostConstruct          (1)
    public void init() {
        bean2.setBean1(this);
    }
}


@Component("bean2")
public class Bean2 {

    private Bean1 bean1;   (2)

    public void setBean1(Bean1 bean1) {
        this.bean1 = bean1;
    }
}
1 Injecting the dependency on another bean using @PostConstruct
2 Do no specify @Autowired as DI is not used for Bean1 in Bean2

5. Get Spring beans programmatically

We can programmatically retrieve a Spring bean either by its name or by its class using ApplicationContext provided by Spring.

A simple bean that uses ApplicationContext to fetch other beans by their name or class, is demonstrated below:

Fetch bean by name or class
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

@Component
public class ContextProvider {

    @Autowired
    private ApplicationContext appContext;

    /**
     * Get a Spring bean by type.
     **/
    public <T> T getBean(Class<T> beanClass) {
        return appContext.getBean(beanClass);
    }

    /**
     * Get a Spring bean by name.
     **/
    public Object getBean(String beanName) {
        return appContext.getBean(beanName);
    }

}

If you do not want to autowire ApplicationContext, then you can implement this interface ApplicationContextAware, which will use setter injection for injecting ApplicationContext into your bean.


Top articles in this category:
  1. Spring DI - Singleton beans with prototype-bean dependencies
  2. Feign RequestInterceptor in Spring Boot
  3. Spring RestTemplate Basic Authentication
  4. SendGrid emails in Spring Boot
  5. Sendgrid Dynamic Templates with Spring Boot
  6. What is difference between Component, Repository, Service, Controller & RestController
  7. Disable SSL validation in Spring RestTemplate

Recommended books for interview preparation:

Find more on this topic:
Buy interview books

Java & Microservices interview refresher for experienced developers.