Why Spring Throws Circular Dependency Errors and How to Fix Them

This article explains the causes of Spring circular dependency exceptions, details how Spring's three‑level cache and AOP proxy mechanisms contribute to the problem, and provides practical solutions such as using @Lazy, refactoring code, and ensuring a single AutoProxyCreator to prevent bean creation failures.

Alibaba Cloud Developer
Alibaba Cloud Developer
Alibaba Cloud Developer
Why Spring Throws Circular Dependency Errors and How to Fix Them

Background

Spring applications often encounter circular dependency exceptions during startup, especially in long‑running, multi‑developer projects.

What is circular dependency?

A circular dependency occurs when two or more beans reference each other directly or indirectly, forming a loop such as A → B → C → A.

Why does it happen?

During bean creation Spring may need to inject a dependency before the bean is fully initialized. If the dependent bean also requires the first bean, Spring tries to resolve the reference using a three‑level cache (singletonObjects, earlySingletonObjects, singletonFactories). Over‑eager type matching or multiple AutoProxyCreator instances can cause mismatched proxy objects, leading to BeanCurrentlyInCreationException.

Supported scenarios

Constructor injection loops (unsupported).

Setter injection for singleton beans (supported).

Prototype beans (cannot be cached, thus unsupported).

Field injection via @Autowired/@Resource (supported).

Three‑level cache explanation

Level 1 : singletonObjects – stores fully initialized singletons.

Level 2 : earlySingletonObjects – stores early references before property population.

Level 3 : singletonFactories – stores ObjectFactory that can create a bean proxy early.

private final Map<String,Object> singletonObjects = new ConcurrentHashMap<>(256);
private final Map<String,Object> earlySingletonObjects = new HashMap<>(16);
private final Map<String,ObjectFactory<?>> singletonFactories = new HashMap<>(16);

Why AOP can still cause circular dependency errors

When a bean participates in AOP, Spring may create a proxy in the third‑level cache. If later initialization creates another proxy (e.g., due to a different AutoProxyCreator), the two proxy instances differ, violating the singleton principle and triggering an exception.

Solutions

Use the original bean when no proxy is required.

Apply @Lazy to defer injection and allow proxy creation only when needed.

Refactor code to extract common logic and eliminate mutual dependencies.

Ensure only one AutoProxyCreator is registered.

Example code

Below is a runnable test demonstrating a circular dependency with @Repository and multiple AutoProxyCreator configurations.

public class MainSpringCircularDependencyTester {
    @Test
    public void springCircularDependencyTest() {
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SpringCircularDependencyConfig.class);
        X x = ac.getBean(X.class);
        x.display();
        // similar for Y and Z
    }
    // configuration and bean classes omitted for brevity
}

Conclusion

Circular dependencies indicate design flaws; they should be resolved by layering, extracting shared modules, or using @Lazy, while understanding Spring’s three‑level cache and AOP proxy mechanics.

AOPSpringCircular DependencyBean Creation
Alibaba Cloud Developer
Written by

Alibaba Cloud Developer

Alibaba's official tech channel, featuring all of its technology innovations.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.