What is circular dependency
Circular DependencyIt refers to two or more beans that depend directly or indirectly on each other, causing the container to fail to initialize these beans normally.
@Service public class ServiceA { @Autowired private ServiceB serviceB; // Service dependency} @Service public class ServiceB { @Autowired private ServiceA serviceA; // Service dependency}
Spring Boot is based on the Spring framework, and its circular dependency processing mechanism is consistent with Spring, but it is default in Spring Boot 2.6+ version.Circular dependency is forbidden(pass-circular-references=false
)。
Causes of circular dependencies
1. Constructor injection loop dependencies:
@Service public class ServiceA { private final ServiceB serviceB; public ServiceA(ServiceB serviceB) { // Constructor injection = serviceB; } } @Service public class ServiceB { private final ServiceA serviceA; public ServiceB(ServiceA serviceA) { // Constructor injection = serviceA; } }
Report an error directly: The circular dependency injected by the constructor cannot be solved, and it is thrown when the container starts
BeanCurrentlyInCreationException
。
2.Setter/Field Injection Circular Dependencies:
Use the @Autowired annotation tag in spring for automatic injection. If it is not processed, a circular dependency problem will occur.
How to solve circular dependencies
Before Springboot 2.5, the circular dependency problem of singleton beans could be solved through level 3 cache.
Cache name | Responsibilities |
---|---|
singletonObjects |
Store fully initialized beans (level one cache) |
earlySingletonObjects |
Store early exposure early beans (L2 cache) |
singletonFactories |
Factory objects that store beans (level three cache) |
Taking the original ServiceA and ServiceB as examples,
Create
ServiceA
, through the factoryQuote for semi-finished productsSave into Level 3 cache.ServiceA
InjectionServiceB
, triggerServiceB
Creation of .Create
ServiceB
, and also store its semi-finished product reference into the third-level cache.ServiceB
InjectionServiceA
When, get from the third level cacheServiceA
Early quotations, completedServiceB
Initialization.ServiceB
After the initialization is completed,ServiceA
Complete dependency injection and finally initialize.
Several solutions after the emergence of circular dependencies:
1.Avoid circular dependencies (recommended)
Refactoring the code: Extract the public logic into the third bean.
Use interfaces or abstract classes: Decoupling through interface-oriented programming.
2. Allow circular dependencies (temporary scheme)
existCircular dependencies are explicitly allowed:
# Spring Boot 2.6+ requires manual activation-circular-references=true
This only applies to cases where the circular dependencies of Springboot version 2.6 or above are prohibited.
3. use@Lazy
Delay loading
Add on one of the dependencies@Lazy
, Delay injection bean initialization:
@Service public class ServiceA { @Lazy @Autowired private ServiceB serviceB; // Delay initialization ServiceB}
4. Adjust the injection method
Priority to Setter/Field injection: Avoid unsolvable circular dependencies caused by constructor injection.
@Service public class ServiceA { private ServiceB serviceB; @Autowired public void setServiceB(ServiceB serviceB) { // Setter injection = serviceB; } }
Use setter injection
Limitations of cyclic dependency
Constructor injection cannot solve circular dependencies: Spring container needs to complete the constructor call first when creating a bean, and the dependency bean has not been initialized at this time.
Prototype scoped beans: Spring does not manage the full life cycle of a prototype bean and cannot resolve its circular dependencies.
AOP proxy problem: If the bean is proxyed by AOP (such as
@Async
、@Transactional
), which may cause circular dependency resolution to fail.
Summarize
The circular dependence essence of Spring Boot is the mechanism problem of the Spring framework. The core solution is:
Understand how Level 3 caching works.
Priority is given to avoid circular dependencies through code design.
Use reasonably if necessary
@Lazy
Or adjust the injection method.
Avoid circular dependencies at the beginning of design as much as possible
This is the end of this article about the reasons and solutions of Springboot circular dependencies. For more related Springboot circular dependencies, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!