[java] Circular dependency in Spring

How does Spring resolve this: bean A is dependent on bean B, and bean B on bean A.

This question is related to java spring

The answer is


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.


Problem ->

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 };
}

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.

What I did was set a conditional breakpoint in AbstractBeanFactory#doGetBean

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:

   System.out.println(ex);
   return false;

Apparently this happens when FactoryBeans are involved in a cyclic dependency graph. We solved it by implementing ApplicationContextAware and InitializingBean and manually injecting the beans.

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class A implements ApplicationContextAware, InitializingBean{

    private B cyclicDepenency;
    private ApplicationContext ctx;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {
        ctx = applicationContext;
    }
    @Override
    public void afterPropertiesSet() throws Exception {
        cyclicDepenency = ctx.getBean(B.class);
    }

    public void useCyclicDependency()
    {
        cyclicDepenency.doSomething();
    }
}

This cut down the startup time to around 15 secs.

So don't always assume that spring can be good at solving these references for you.

For this reason I'd recommend disabling cyclic dependency resolution with AbstractRefreshableApplicationContext#setAllowCircularReferences(false) to prevent many future problems.


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


Circular dependency in Spring : Dependency of one Bean to other. Bean A ? Bean B ? Bean A

Solutions:

  1. Use @Lazy Annotation
  2. Redesign you class dependency
  3. Use Setter/Field Injection
  4. Use @PostConstruct Annotation

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.


It just does it. It instantiates a and b, and injects each one into the other (using their setter methods).

What's the problem?


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;
    }

}

If you then had this configuration file:

<bean id="a" class="mypackage.A">
    <property name="b" ref="b" />
</bean>

<bean id="b" class="mypackage.B">
    <property name="a" ref="a" />
</bean>

You would see the following output when creating a context using this configuration:

Creating instance of A
Creating instance of B
Setting property a of B instance
Setting property b of A instance

Note that when a is injected into b, a is not yet fully initialised.


From the Spring Reference:

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.


Its clearly explained here. Thanks to Eugen Paraschiv.

Circular dependency is a design smell, either fix it or use @Lazy for the dependency which causes problem to workaround it.


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'

Refer Spring doc at "https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#resources-resource"