In this post we’ll see what is circular dependency in Spring and how to resolve circular dependencies.
Circular dependency in Spring
If you mostly use constructor dependency injection, it is possible to create an unresolvable circular dependency scenario. For example; Class A requires an instance of class B through constructor injection, and class B requires an instance of class A through constructor injection. In such configuration where beans for classes A and B are to be injected into each other, the Spring IoC container can’t decide which bean should be created first and throws BeanCurrentlyInCreationException at runtime when it detects this circular reference.
Circular dependency Spring example
Here is an example showing how circular dependency may occur in your application.
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class ClassA { private ClassB b; @Autowired ClassA(ClassB b){ this.b = b; } }
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class ClassB { private ClassA a; @Autowired ClassB(ClassA a){ this.a = a; } }
There are two classes ClassA and ClassB, ClassA has a dependency on ClassB and ClassB has a dependency on ClassA and theses dependencies are injected as constructor dependencies.
Following Spring XML configuration sets up the component scanning.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="com.knpcode.springproject.service"/> </beans>
You can use the following class with main method to read the configuration and run the example.
import org.springframework.context.support.ClassPathXmlApplicationContext; public class App { public static void main( String[] args ){ // create context using configuration ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("appcontext.xml"); } }
On running the example program you will get an exception similar to as given below because of the circular reference.
11:08:12.031 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'classB' 11:08:12.039 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'classA' Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'classA' defined in file [F:\knpcode\Spring WorkSpace\SpringProject\target\classes\com\knpcode\springproject\service\ClassA.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'classB' defined in file [F:\knpcode\Spring WorkSpace\SpringProject\target\classes\com\knpcode\springproject\service\ClassB.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'classA': Requested bean is currently in creation: Is there an unresolvable circular reference? at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:769) at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:218) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1341) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1187) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:845) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:877) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549) at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:144) at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:85) at com.knpcode.springproject.App.main(App.java:10) Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'classB' defined in file [F:\knpcode\Spring WorkSpace\SpringProject\target\classes\com\knpcode\springproject\service\ClassB.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'classA': Requested bean is currently in creation: Is there an unresolvable circular reference? at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:769) at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:218) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1341) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1187) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:277) at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1251) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1171) at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:857) at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:760) ... 15 more
Resolving circular dependency
In many cases by redesigning classes you can avoid circular dependencies. If you have to have such object dependencies then with in Spring to avoid circular dependencies you can use one of the following solutions.
1. Use setter injection instead of constructor injection. When setter injection is used dependencies are injected only when they are used not at the bean creation time.
@Component public class ClassA { private ClassB b; @Autowired public void setB(ClassB b) { this.b = b; } public void display() { System.out.println("In method of classA"); } }
@Component public class ClassB { private ClassA a; @Autowired public void setA(ClassA a) { this.a = a; } public void display() { System.out.println("In method of classB"); } }
As you can see now the dependencies are injected as setter dependencies.
On running the application
public class App { public static void main( String[] args ){ // create context using configuration ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("appcontext.xml"); ClassA a = context.getBean("classA", ClassA.class); a.display(); context.close(); } }Output
:24:06.884 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'classA' 11:24:07.019 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'classB' 11:24:07.038 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'employeeService' In method of classA
2. Another way to avoid circular dependency in Spring is to lazy initialize one of the bean. That way even with constructor injection bean is fully initialized only when it is needed.
Here is updated classA where @Lazy
is also used with @Autowired, it leads to the creation of a
lazy-resolution proxy for the dependencies.
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; @Component public class ClassA { private ClassB b; @Autowired @Lazy ClassA(ClassB b){ this.b = b; } public void display() { System.out.println("In method of classA"); } }
That's all for the topic Circular Dependency in Spring. If something is missing or you have something to share about the topic please write a comment.
You may also like
- Spring IoC Container Types – ApplicationContext and BeanFactory
- Injecting Null and Empty String Values in Spring
- Spring Boot Microservices Example
- Selection Sort Java Program
- Java throws Clause With Examples
- Phaser in Java With Examples
- Java Program to Compress File in bzip2 Format in Hadoop
- First React App – Hello World React Example
No comments:
Post a Comment