How to Resolve Circular Dependency in Spring Boot.

In this blog post we will see various ways to resolve circular dependency while working with Spring Boot application.

Let’s look at the one example of circular dependency .

@Component public class A { private B b; public A( B b) { this.b = b; } }
Code language: Java (java)
@Component public class B { private A a; public B(A a){ this.a = a; } }
Code language: Java (java)

If you start the application, you will see following error in your startup log.

2023-02-20T23:59:19.674+13:00 WARN 14376 --- [ main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'a' defined in file [D:\IdeaProjects\sb-circular-dependency\target\classes\dev\fullstackcode\sb\component\A.class]: Unsatisfied dependency expressed through constructor parameter 0: Error creating bean with name 'b' defined in file [D:\IdeaProjects\sb-circular-dependency\target\classes\dev\fullstackcode\sb\component\B.class]: Unsatisfied dependency expressed through constructor parameter 0: Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference? 2023-02-20T23:59:19.679+13:00 INFO 14376 --- [ main] o.apache.catalina.core.StandardService : Stopping service [Tomcat] 2023-02-20T23:59:19.698+13:00 INFO 14376 --- [ main] .s.b.a.l.ConditionEvaluationReportLogger : Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled. 2023-02-20T23:59:19.731+13:00 ERROR 14376 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPLICATION FAILED TO START *************************** Description: The dependencies of some of the beans in the application context form a cycle: ┌─────┐ | a defined in file [D:\IdeaProjects\sb-circular-dependency\target\classes\dev\fullstackcode\sb\component\A.class] ↑ ↓ | b defined in file [D:\IdeaProjects\sb-circular-dependency\target\classes\dev\fullstackcode\sb\component\B.class] └─────┘ Action: Relying upon circular references is discouraged and they are prohibited by default. Update your application to remove the dependency cycle between beans. As a last resort, it may be possible to break the cycle automatically by setting spring.main.allow-circular-references to true. Process finished with exit code 1
Code language: Java (java)

Now look at the solutions to to resolve the circular dependency issue.

Use @Lazy Annotation

If you do not want to change any existing code you can use @Lazy annotation on one of the construction injections.

@Component public class A { private B b; public A( B b) { this.b = b; } }
Code language: Java (java)
@Component public class B { private A a; public B(@Lazy A a){ this.a = a; } }
Code language: Java (java)

Use setter Injections

Instead of using the constructor injections, you can use setter injection and se

@Component public class A { @Autowired private B b; }
Code language: Java (java)
@Component public class B { @Autowired private A a; }
Code language: Java (java)

With setter injection, you also need to use following property in the application.properties file.

spring.main.allow-circular-references=true
Code language: Java (java)

User @PostConstruct method

You can refactor the code to set the bean from the method with @PostConstruction annotation.

@Component public class A { private B b; public A(B b) { this.b = b; } @PostConstruct public void init() { b.setA(this); } }
Code language: Java (java)

@Component public class B { private A a; public void setA(A a){ this.a = a; } }
Code language: Java (java)

Using afterPropertiesSet method

You can refactor the code to get the bean from application context and set the bean from afterPropertiesSet method.

@Component public class A implements ApplicationContextAware, InitializingBean { private B b; private ApplicationContext ctx; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.ctx = applicationContext; } @Override public void afterPropertiesSet() throws Exception { this.b = ctx.getBean(B.class); this.b.setA(this); } }
Code language: Java (java)
@Component public class B { private A a; public void setA(A a) { this.a = a; } }
Code language: Java (java)

Similar Posts