Monday, 6 February 2017

Spring: Circular Dependency problem

What is Circular Dependency Problem?
Circular dependency is a relation between two or more modules which either directly or indirectly depend on each other to function properly. Let me explain with an example.

Suppose there are two classes A and B. A is dependent on B and B is dependent on A.

As you see the constructor of class ‘A’, it initialize object of class B, that means A is dependent on B.

As you see the constructor of class ‘B’, it initialize object of class A, that means B is dependent on A.

A is dependent on B and B is dependent on A. This is called circular dependency problem.

What happen if you try to instantiate class A (or) B?
Let us try to define object for class A, the constructor of class A calls the constructor of class B. The constructor of class B calls the constructor of class A. This is an infinite recursion call, finally application end up in  StackOverflowError. Spring throws ‘BeanInstantiationException’ in case of circular dependency.

A.java
package com.sample.pojo;

public class A {
 private B b;

 public A() {
  this.b = new B();
 }
}

B.java
package com.sample.pojo;

public class B {
 private A a;

 public B() {
  this.a = new A();
 }
}

myConfiguration.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

 <bean id="a" name="objA" class="com.sample.pojo.A" />

</beans>

HelloWorld.java

package com.sample.test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.sample.pojo.A;

public class HelloWorld {
 public static void main(String args[]) {
  ApplicationContext context = new ClassPathXmlApplicationContext(new String[] { "myConfiguration.xml" });

  A obj1 = context.getBean("a", A.class);

  System.out.println(obj1);

  ((ClassPathXmlApplicationContext) context).close();
 }
}

Run HelloWorld.java, you will end up in following error.

Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'a' defined in class path resource [myConfiguration.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.sample.pojo.A]: Constructor threw exception; nested exception is java.lang.StackOverflowError
 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1110)
 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1055)
 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:510)
 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
 at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
 at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
 at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
 at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
 at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:751)
 at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:861)
 at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:541)
 at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
 at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:93)
 at com.sample.test.HelloWorld.main(HelloWorld.java:10)
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.sample.pojo.A]: Constructor threw exception; nested exception is java.lang.StackOverflowError
 at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:154)
 at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:89)
 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1103)
 ... 13 more
Caused by: java.lang.StackOverflowError
 at com.sample.pojo.B.<init>(B.java:6)
 at com.sample.pojo.A.<init>(A.java:7)
 at com.sample.pojo.B.<init>(B.java:7)
 at com.sample.pojo.A.<init>(A.java:7)
 at com.sample.pojo.B.<init>(B.java:7)
 at com.sample.pojo.A.<init>(A.java:7)
 at com.sample.pojo.B.<init>(B.java:7)
 at com.sample.pojo.A.<init>(A.java:7)
 at com.sample.pojo.B.<init>(B.java:7)
 at com.sample.pojo.A.<init>(A.java:7)
 at com.sample.pojo.B.<init>(B.java:7)
 at com.sample.pojo.A.<init>(A.java:7)
 at com.sample.pojo.B.<init>(B.java:7)
 at com.sample.pojo.A.<init>(A.java:7)
 at com.sample.pojo.B.<init>(B.java:7)

How to resolve Circular dependency?
There are two ways to resolve this problem.
a.   Removing the dependency from constructor definition
b.   Point the circular dependency to current object

Removing the dependency from constructor definition
Define the dependencies using setter methods like below.


A.java

public class A {
 private B b;

 public A() {

 }

 public void setB(B b) {
  this.b = b;
 }

}

B.java

public class B {
 private A a;

 public B() {

 }

 public void setA(A a) {
  this.a = a;
 }

}

Point the circular dependency to current object

Update classes A and B like below.

public class A {
 private B b;

 public A() {
  b = new B(this);
 }

}


public class B {
 private A a;

 public B(A a) {
  this.a = a;
 }

}



Previous                                                 Next                                                 Home

No comments:

Post a Comment