Spring IOC容器:Bean生命周期与循环依赖解决
Spring IOC容器:Bean生命周期与循环依赖解决
引言
在Java企业级开发领域,Spring框架无疑占据了统治地位,而控制反转作为Spring的核心思想,贯穿了框架的始终。对于大多数开发者而言,日常工作中可能只需要通过@Autowired注解就能完成依赖注入,似乎无需深究其底层实现。然而,当我们在面试中面对“请描述Bean的生命周期”或“Spring是如何解决循环依赖的”这类问题时,或者在生产环境中遇到Bean初始化顺序异常、循环依赖报错等棘手问题时,深入理解IOC容器的内部机制就显得尤为重要。
本文将从源码级别深入剖析Spring Bean的生命周期全过程,并详细解读Spring解决循环依赖的“三级缓存”机制。这不仅是面试的高频考点,更是从“API调用者”进阶为“框架掌控者”的必经之路。
核心概念:Bean的生命周期
Spring Bean的生命周期并不是简单的“创建->使用->销毁”,而是一个复杂且精密的流程。我们可以将其概括为四大阶段:实例化、属性赋值、初始化 和 销毁。
1. 实例化
这是Bean诞生的第一步。Spring会根据BeanDefinition中的信息,通过构造函数反射创建Bean的实例对象。此时对象仅仅是在堆内存中分配了空间,属性均为默认值,是一个“半成品”。
2. 属性赋值
实例化完成后,容器会扫描Bean的属性,将配置的属性值或依赖的其他Bean注入到当前Bean中。这就是我们常说的依赖注入(DI)发生的主要阶段。
3. 初始化
这是生命周期中最复杂、扩展性最强的阶段,包含了多个回调接口的调用:
* Aware接口回调:如果Bean实现了BeanNameAware、BeanFactoryAware等接口,Spring会将Bean名称或容器本身注入给Bean,让Bean感知到容器的存在。
* BeanPostProcessor(前置处理):执行postProcessBeforeInitialization方法。这是Spring留给开发者的扩展点,可以在初始化前对Bean进行修改。
* InitializingBean与init-method:如果Bean实现了InitializingBean接口,会调用afterPropertiesSet()方法;如果定义了init-method,也会在此执行。通常用于执行自定义初始化逻辑。
* BeanPostProcessor(后置处理):执行postProcessAfterInitialization方法。这是最关键的一步,Spring的AOP代理对象就是在此处生成的。
4. 销毁
当容器关闭时,会执行销毁逻辑。包括DisposableBean接口的destroy()方法和自定义的destroy-method。
技术原理:循环依赖与三级缓存
循环依赖是指Bean A依赖Bean B,而Bean B又依赖Bean A(或更长的闭环)。在单例模式下,Spring通过三级缓存机制解决了构造器注入以外的循环依赖问题。
三级缓存架构
Spring在DefaultSingletonBeanRegistry中维护了三个Map结构:
- 一级缓存 (
singletonObjects):存放已经完全初始化好的Bean(成品)。 - 二级缓存 (
earlySingletonObjects):存放提前暴露的Bean实例,但尚未完成属性填充和初始化(半成品)。 - 三级缓存 (
singletonFactories):存放ObjectFactory,用于生成早期Bean对象,主要目的是处理AOP代理。
解决流程解析
假设A、B两个Bean相互依赖:
- 创建A:A开始实例化,调用构造函数。
- 暴露A:A实例化完成后,将A的ObjectFactory放入三级缓存。
- 注入B:A开始填充属性,发现依赖B,尝试获取B。
- 创建B:B不存在,开始实例化B。
- 注入A:B开始填充属性,发现依赖A,尝试获取A。
- 获取A:B在一级缓存找不到A,去二级缓存也找不到,最终在三级缓存中找到A的ObjectFactory。通过工厂获取到A的早期对象(如果A需要代理,这里返回的是代理对象),并将其放入二级缓存,删除三级缓存。
- B完成:B持有A的引用,完成初始化,放入一级缓存。
- A完成:A继续执行,获取到已完成的B,完成初始化,放入一级缓存。
为什么需要三级缓存?
如果仅仅是解决循环依赖,二级缓存足矣。三级缓存的存在是为了处理AOP代理。如果在创建过程中就需要注入代理对象,三级缓存中的ObjectFactory可以智能地决定是返回原始对象还是代理对象,保证了Bean在整个生命周期中的一致性。
实战代码
下面的代码演示了Bean生命周期的完整流程,并通过日志验证了执行顺序。
1. 定义生命周期Bean
```java
package com.example.springdemo;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.*;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
/*
* 演示Spring Bean生命周期的完整流程
* 实现了Spring提供的一系列感知接口和生命周期接口
/
public class LifecycleBean implements BeanNameAware, BeanFactoryAware,
ApplicationContextAware, InitializingBean, DisposableBean {
private String property;
// 1. 构造函数:实例化阶段
public LifecycleBean() {
System.out.println("1. [构造函数] Bean实例化...");
}
// Setter方法:用于演示属性赋值(XML或注解方式注入)
public void setProperty(String property) {
System.out.println("2. [属性赋值] 注入属性值: " + property);
this.property = property;
}
// 3. BeanNameAware接口:感知Bean的名称
@Override
public void setBeanName(String name) {
System.out.println("3. [Aware接口] BeanNameAware -> Bean名称: " + name);
}
// 4. BeanFactoryAware接口:感知BeanFactory
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("4. [Aware接口] BeanFactoryAware -> 持有BeanFactory引用");
}
// 5. ApplicationContextAware接口:感知ApplicationContext
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("5. [Aware接口]

浙公网安备 33010602011771号