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; } }
No comments:
Post a Comment