Circular dependency in Spring

JavaSpring

Java Problem Overview


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

Java Solutions


Solution 1 - Java

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.

Solution 2 - Java

As the other answers have said, Spring just takes care of it, creating the beans and injecting them as required.

One of the consequences is that bean injection / property setting might occur in a different order to what your XML wiring files would seem to imply. So you need to be careful that your property setters don't do initialization that relies on other setters already having been called. The way to deal with this is to declare beans as implementing the InitializingBean interface. This requires you to implement the afterPropertiesSet() method, and this is where you do the critical initialization. (I also include code to check that important properties have actually been set.)

Solution 3 - Java

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.

Solution 4 - Java

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

Solution 5 - Java

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

What's the problem?

Solution 6 - Java

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.

Solution 7 - Java

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.

Solution 8 - Java

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.

Solution 9 - Java

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.

Solution 10 - Java

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

Solution 11 - Java

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

Solution 12 - Java

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.

Solution 13 - Java

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"

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionfastcodejavaView Question on Stackoverflow
Solution 1 - JavaRichard FearnView Answer on Stackoverflow
Solution 2 - JavaStephen CView Answer on Stackoverflow
Solution 3 - JavajontejjView Answer on Stackoverflow
Solution 4 - JavaAkshay N. ShelkeView Answer on Stackoverflow
Solution 5 - JavaskaffmanView Answer on Stackoverflow
Solution 6 - JavaSilentView Answer on Stackoverflow
Solution 7 - JavaearldouglasView Answer on Stackoverflow
Solution 8 - JavaSaurav S.View Answer on Stackoverflow
Solution 9 - JavawhoamiView Answer on Stackoverflow
Solution 10 - JavaRitu GuptaView Answer on Stackoverflow
Solution 11 - JavabarclarView Answer on Stackoverflow
Solution 12 - JavaPremrajView Answer on Stackoverflow
Solution 13 - JavaSrikant MView Answer on Stackoverflow