Backend Development 14 min read

How Spring’s Three‑Level Cache Solves Circular Dependencies

This article explains what circular dependencies are in Spring, describes the three‑level cache mechanism (singletonObjects, earlySingletonObjects, singletonFactories), shows how it resolves singleton bean cycles, and outlines scenarios where the cache cannot break the dependency, such as constructor injection and prototype beans.

Sanyou's Java Diary
Sanyou's Java Diary
Sanyou's Java Diary
How Spring’s Three‑Level Cache Solves Circular Dependencies

1. What Is a Circular Dependency

When two services, e.g., AService and BService , reference each other, a circular dependency occurs. The article shows typical code snippets (illustrated with diagrams) where each class autowires the other.

2. Scenarios Solved by the Three‑Level Cache

The three‑level cache can resolve the above field‑injection cycle. Setter injection works as well, as shown in the diagram.

3. How Spring Creates a Bean

The bean creation process consists of several stages: BeanDefinition reading, instantiation, property population (where @Autowired is applied), and initialization (including callbacks and proxy creation). The article provides a flow diagram.

4. The Three Levels of Cache

First level (singletonObjects) : stores fully created singleton beans.

Second level (earlySingletonObjects) : holds early‑exposed beans that are not yet fully initialized, enabling circular references.

Third level (singletonFactories) : contains ObjectFactory instances that can produce early beans on demand. This cache works only for singleton beans.

5. How the Cache Breaks the Cycle

When AService is instantiated, its ObjectFactory is placed in the third‑level cache. When BService needs AService , Spring looks through the three caches, finds the factory, obtains the early bean, stores it in the second‑level cache, and injects it into BService . After both beans are fully created, they are moved to the first‑level cache and the secondary caches are cleared.

6. Cases the Cache Cannot Solve

1) Constructor injection : The bean is needed before it is instantiated, so the third‑level cache is never populated, leading to a startup error.

2) Prototype (non‑singleton) beans : The cache works only for singletons; prototype beans trigger an exception when a circular reference is detected.

7. Why Not Use Only Two Levels of Cache?

Removing the third level would force early exposure of bean instances or proxies, which can cause mismatches between early and fully created beans and lead to startup failures. Removing the second level would require repeatedly creating proxies via the factory, also causing inconsistencies. Hence both secondary caches are necessary.

Article ends.

Springdependency injectionCircular DependencyThree-level Cachebean lifecycle
Sanyou's Java Diary
Written by

Sanyou's Java Diary

Passionate about technology, though not great at solving problems; eager to share, never tire of learning!

0 followers
Reader feedback

How this landed with the community

login 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.