Backend Development 8 min read

Understanding Spring Bean Lifecycle and Circular Dependency Resolution

This article explains the core concepts of the Spring framework—including its container, bean definition readers, bean factories, and three‑level cache mechanism—while detailing how Spring resolves circular dependencies and integrates AOP during bean creation.

Top Architect
Top Architect
Top Architect
Understanding Spring Bean Lifecycle and Circular Dependency Resolution

Spring is a container that holds various beans and serves as the foundation for extensions like SpringBoot and SpringCloud.

The Spring IoC container can be viewed as a map storing bean definitions, and its overall workflow involves reading bean definitions via BeanDefinitionReader implementations such as XmlBeanDefinitionReader , PropertiesBeanDefinitionReader , and GroovyBeanDefinitionReader .

BeanFactory is the root interface for accessing the bean container, with implementations like ApplicationContext and BeanFactoryPostProcessor that manipulate bean definitions.

During bean creation, Spring follows a multi‑step process: instantiate the bean, populate its properties, and then initialize it. Aware interfaces (e.g., ApplicationContextAware ) allow beans to obtain container references, while BeanPostProcessor implementations (e.g., AbstractAutoProxyCreator ) enable AOP extensions.

Spring Circular Dependency Problem

A circular dependency occurs when bean A depends on bean B and bean B depends on bean A, similar to a deadlock. Spring resolves this by classifying bean creation states into three caches (a three‑level cache):

SingletonObjects (first‑level cache) stores fully initialized beans.

EarlySingletonObjects (second‑level cache) stores partially created beans (instantiated but not yet initialized).

SingletonFactories (third‑level cache) stores factories (lambda expressions) that can produce bean instances on demand.

The three‑level cache is illustrated in the following code snippet:

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry { ... /** Cache of singleton objects: bean name to bean instance. */ private final Map
singletonObjects = new ConcurrentHashMap<>(256); /** Cache of singleton factories: bean name to ObjectFactory. */ private final Map
> singletonFactories = new HashMap<>(16); /** Cache of early singleton objects: bean name to bean instance. */ private final Map
earlySingletonObjects = new ConcurrentHashMap<>(16); ... }

When a bean is needed, Spring first checks the second‑level cache; if the bean is a candidate for AOP proxying, it uses the lambda stored in the third‑level cache to create the proxy early, ensuring that circular references receive the correct proxied instances without breaking the bean lifecycle design.

Key Takeaways

Spring’s three‑level cache, combined with lambda‑based factories, allows the framework to resolve circular dependencies while preserving the intended order of bean instantiation, property injection, initialization, and AOP proxy creation.

BackendJavaAOPSpringdependency injectionbean lifecycle
Top Architect
Written by

Top Architect

Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.

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.