SoFunction
Updated on 2025-05-05

Spring Level 3 cache resolution process

1. Circular dependency scenario

Assume that there is an interdependence between two beans:

@Component
public class ServiceA {
    @Autowired
    private ServiceB serviceB;
}

@Component
public class ServiceB {
    @Autowired
    private ServiceA serviceA;
}

Level 2 and Level 3 cache definition

existDefaultSingletonBeanRegistryDefinition in:

// Level 1 cache: complete bean (K:Bean name V: instantiation + initialization bean)private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

// Level 2 cache: Early exposure object (K:Bean name V: Original bean with unfinished attribute injection)private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

// Level 3 cache: Object factory (K:Bean name V:ObjectFactory)private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

3. Solution process (taking ServiceA and ServiceB as examples)

1. Create a Service

sequenceDiagram
    participant Container
    participant Cache1 as singletonObjects
    participant Cache2 as earlySingletonObjects
    participant Cache3 as singletonFactories
    
    Container->>Cache1: examineServiceADoes it exist
    Cache1-->>Container: Does not exist
    Container->>Container: InstantiationServiceA(Constructor call)
    Container->>Cache3: Add toServiceAofObjectFactory
    Container->>Container: Start attribute injection(needServiceB)

Key code segments

// AbstractAutowireCapableBeanFactory#doCreateBean
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));

2. Found that ServiceB is required

sequenceDiagram
    participant Container
    participant Cache1
    participant Cache2
    participant Cache3
    
    Container->>Cache1: examineServiceBDoes it exist
    Cache1-->>Container: Does not exist
    Container->>Container: InstantiationServiceB(Constructor call)
    Container->>Cache3: Add toServiceBofObjectFactory
    Container->>Container: Start attribute injection(needServiceA)

3. Solve ServiceB's dependence on ServiceA

sequenceDiagram
    participant Container
    participant Cache1
    participant Cache2
    participant Cache3
    
    Container->>Cache1: FindServiceA
    Cache1-->>Container: Does not exist
    Container->>Cache2: FindServiceA
    Cache2-->>Container: Does not exist
    Container->>Cache3: GetServiceAofObjectFactory
    Container->>Container: implementgetEarlyBeanReference()
    Container->>Cache2: Will生成of代理对象存入earlySingletonObjects
    Container->>ServiceB: injectionServiceAof早期引用
    Container->>Container: FinishServiceBinitialization
    Container->>Cache1: WillServiceBPut insingletonObjects

4. Backtracking complete ServiceA initialization

sequenceDiagram
    participant Container
    participant Cache1
    participant Cache2
    participant Cache3
    
    Container->>ServiceA: Inject initializedServiceB
    Container->>Container: implementServiceAThe initialization method
    Container->>Cache1: WillServiceAPut insingletonObjects
    Container->>Cache2: RemoveServiceAEarly citations
    Container->>Cache3: RemoveServiceAofObjectFactory

4. Detailed explanation of key mechanisms

1. The core role of getEarlyBeanReference()

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
    // Generate proxy objects here if necessary    if (!() && hasInstantiationAwareBeanPostProcessors()) {
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                SmartInstantiationAwareBeanPostProcessor ibp = 
                    (SmartInstantiationAwareBeanPostProcessor) bp;
                bean = (exposedObject, beanName);
            }
        }
    }
    return bean;
}

2. Analysis of the necessity of level 3 cache

Cache Level Problems solved Typical scenarios
singletonFactories Handle delayed generation of AOP proxy A singleton of proxy objects needs to be guaranteed
earlySingletonObjects Avoid duplicate creation of early references Multiple Beans depend on the same bean that has not been initialized
singletonObjects Storage of the ultimate bean available Normal bean acquisition

V. Design constraints and limitations

1. Only singleton scopes are supported

Prototype scoped beans cannot solve circular dependencies because Spring does not cache prototype beans

2. Constructor injection limit

If the circular dependency occurs through the constructor injection, it cannot be resolved (dependency injection needs to be completed before instantiation)

3. Risk of asynchronous initialization

use@AsyncBeans enhanced by methods such as the may destroy the initialization order

6. Debugging skills

Check cache status 

existDefaultSingletonBeanRegistrySet breakpoints in the class:

// View Level 3 cache content("singletonFactories: " + ());
("earlySingletonObjects: " + ());
("singletonObjects: " + ());

Forced throwing a circular dependency exception

Add in the configuration class:

@Bean
public CircularReferencesBean circularReferencesBean() {
    return new CircularReferencesBean(circularReferencesBean());
}

7. Performance optimization suggestions

Avoid overuse of circular dependencies

Even if the technology is feasible, it should be decoupled through design patterns (such as event-driven)

Use @Lazy annotation reasonably

Lazy loading non-essential dependencies:

@Autowired
@Lazy
private ServiceB serviceB;

Monitor cache hit rate

Monitoring via JMXsingletonObjectsandearlySingletonObjectsThe ratio of

Summarize

Spring's Level 3 caching mechanism passesExpose object references in advance + Dynamic proxy generationThe collaborative design of the system elegantly solves the circular dependency problem while ensuring singletonity. Understanding this mechanism requires focusing on the stage division of the Bean life cycle and the transformation logic of cache state.

The above is personal experience. I hope you can give you a reference and I hope you can support me more.