Lesson 52 · Spring 生态核心原理
Spring IoC 容器原理:BeanFactory 与 ApplicationContext
面试官:Spring IoC 的原理是什么?
IoC(Inversion of Control)是 Spring 的灵魂,但大多数人停留在「控制反转 = 把 new 对象的权力交给容器」这一层。真正的面试深度回答需要覆盖:
- 概念层:IoC 与 DI 的精确区分
- 接口层:BeanFactory → ApplicationContext 的继承体系与职责差异
- 流程层:容器启动 refresh() 的 12 步、Bean 创建的完整链路
- 元模型:BeanDefinition 如何描述一个 Bean 的全部元信息
- 难点:三级缓存与循环依赖(本文预告,专文展开)
本文逐站深入,从概念到源码,给出可直接在面试中复述的完整回答。
IoC 与 DI:不是一回事
很多人把 IoC 和 DI 混为一谈,但面试中精确区分它们是加分项:
| 维度 | IoC(控制反转) | DI(依赖注入) |
|---|---|---|
| 本质 | 一种设计思想 | IoC 的一种具体实现方式 |
| 含义 | 对象的创建、装配、生命周期由容器控制,而非程序代码直接管理 | 容器在运行时将依赖对象「注入」到组件中 |
| 对立面 | 程序自己 new 对象 | 程序自己查找依赖(Service Locator 模式) |
| 关系 | IoC ⊃ DI(DI 是 IoC 的子集) | IoC 的实现方式之一(另一种是 Service Locator) |
DI 的三种注入方式:
// ① 构造器注入(推荐:不可变、可测试、保证非空)
public class OrderService {
private final UserRepository userRepo;
public OrderService(UserRepository userRepo) {
this.userRepo = userRepo;
}
}
// ② Setter 注入(可选依赖、运行时可变)
public class OrderService {
private UserRepository userRepo;
@Autowired
public void setUserRepo(UserRepository userRepo) {
this.userRepo = userRepo;
}
}
// ③ 字段注入(最方便,但不推荐:不可变差、难测试)
public class OrderService {
@Autowired
private UserRepository userRepo;
}
BeanFactory vs ApplicationContext:接口体系
Spring 容器的核心接口不只有一个 BeanFactory,而是一棵继承树。理解这棵树是理解容器能力的钥匙:
| 能力 | BeanFactory | ApplicationContext |
|---|---|---|
| Bean 实例化 / 依赖注入 | ✓ | ✓ |
| Bean 初始化策略 | 懒加载(getBean 时创建) | 启动时预创建所有单例 |
| 国际化(i18n / MessageSource) | ✗ | ✓ |
| 事件发布(ApplicationEvent) | ✗ | ✓ |
| AOP 自动代理 | 需手动配置 | ✓ 自动集成 |
| 资源加载(Resource) | ✗ | ✓ |
| 注解支持(@Autowired 等) | 需注册后处理器 | ✓ 默认开启 |
容器启动流程:refresh() 十二步
Spring 容器启动的核心入口是 AbstractApplicationContext.refresh()。这个方法只有不到 100 行,却编排了整个 Spring 的启动逻辑。面试中被问到的概率极高:
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// ① 准备刷新:校验必要属性、初始化 PropertySources
prepareRefresh();
// ② 获取 BeanFactory:解析 XML/注解,注册 BeanDefinition
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// ③ 准备 BeanFactory:设置类加载器、注册标准 Bean
prepareBeanFactory(beanFactory);
try {
// ④ 子类扩展点:注册容器级后处理器
postProcessBeanFactory(beanFactory);
// ⑤ 执行 BeanFactoryPostProcessor(如 PropertyPlaceholder)
invokeBeanFactoryPostProcessors(beanFactory);
// ⑥ 注册 BeanPostProcessor(如 AutowiredAnnotationBPP)
registerBeanPostProcessors(beanFactory);
// ⑦ 初始化国际化 MessageSource
initMessageSource();
// ⑧ 初始化事件广播器
initApplicationEventMulticaster();
// ⑨ 子类扩展点(如 SpringBoot 在此启动内嵌 Tomcat)
onRefresh();
// ⑩ 注册事件监听器
registerListeners();
// ⑪ 实例化所有非懒加载的单例 Bean ★最重的一步
finishBeanFactoryInitialization(beanFactory);
// ⑫ 发布 ContextRefreshedEvent、注册 JMX 等收尾
finishRefresh();
} catch (BeansException ex) {
destroyBeans();
cancelRefresh(ex);
throw ex;
}
}
}
第 ⑤ 步执行的是 BeanFactoryPostProcessor,它作用于 BeanFactory 本身(如替换占位符 ${...});第 ⑥ 步注册的是 BeanPostProcessor,它作用于每个 Bean 实例(如 @Autowired 注入、AOP 代理)。二者执行的时机和作用对象完全不同。
BeanDefinition:Bean 的元数据模型
Spring 容器并不直接存储你的 Bean 类,而是存储一份描述这个 Bean 的元数据对象——BeanDefinition。就像数据库的 Schema 描述表结构一样,BeanDefinition 描述 Bean 的全部配置信息:
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
// Bean 的全限定类名
String getBeanClassName();
// 作用域:singleton / prototype / request / session
String getScope();
// 是否懒加载
boolean isLazyInit();
// 依赖的其他 Bean(保证创建顺序)
String[] getDependsOn();
// 构造器参数
ConstructorArgumentValues getConstructorArgumentValues();
// 属性值(setter 注入)
MutablePropertyValues getPropertyValues();
// 初始化 / 销毁方法
String getInitMethodName();
String getDestroyMethodName();
}
BeanDefinition 从哪来?三大解析路径:
| 配置方式 | 解析器 | 说明 |
|---|---|---|
| XML 配置 | XmlBeanDefinitionReader | 解析 <bean> 标签 |
| 注解配置 | AnnotatedBeanDefinitionReader | 解析 @Component / @Bean |
| Java Config | ConfigurationClassPostProcessor | 解析 @Configuration 类 |
所有解析结果都注册到 BeanDefinitionRegistry(本质是一个 ConcurrentHashMap<String, BeanDefinition>):
public class DefaultListableBeanFactory
extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry {
// ★ BeanDefinition 的最终存储地
private final Map<String, BeanDefinition> beanDefinitionMap
= new ConcurrentHashMap<>(256);
// 保持注册顺序的 Bean 名称列表
private volatile List<String> beanDefinitionNames
= new ArrayList<>(256);
}
配置源(XML / @Component / @Bean) →
BeanDefinitionReader 解析 → BeanDefinition 对象 → 注册到 BeanDefinitionRegistry(Map) → 容器启动时按 BeanDefinition 创建 Bean 实例Bean 创建流程:从 getBean 到完整实例
当容器执行到 refresh() 的第 ⑪ 步 finishBeanFactoryInitialization() 时,会遍历所有非懒加载的单例 BeanDefinition,逐个调用 getBean()。完整链路如下:
// 入口:外部调用或容器内部触发
public Object getBean(String name) {
return doGetBean(name, null, null, false);
}
protected <T> T doGetBean(String name, ...) {
// ① 先查三级缓存(处理循环依赖)
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null) return (T) sharedInstance;
// ② 检查并创建依赖的 Bean(depends-on)
String[] dependsOn = mbd.getDependsOn();
for (String dep : dependsOn) getBean(dep);
// ③ 根据 scope 创建 Bean
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
return createBean(beanName, mbd, args);
});
}
return (T) sharedInstance;
}
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) {
// 解析 Bean 的 Class(处理 FactoryBean 等情况)
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
return doCreateBean(beanName, mbd, args);
}
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, Object[] args) {
// ──── 阶段 1:实例化 ────
BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args);
Object bean = instanceWrapper.getWrappedInstance();
// ★ 提前暴露到三级缓存(解决循环依赖的关键)
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
// ──── 阶段 2:属性填充 ────
populateBean(beanName, mbd, instanceWrapper);
// ──── 阶段 3:初始化 ────
Object exposedBean = initializeBean(beanName, bean, mbd);
// ├─ invokeAwareMethods() → BeanNameAware, BeanFactoryAware
// ├─ applyBeanPostProcessorsBeforeInitialization() → @PostConstruct
// ├─ invokeInitMethods() → InitializingBean.afterPropertiesSet(), init-method
// └─ applyBeanPostProcessorsAfterInitialization() → AOP 代理在此生成
return exposedBean;
}
Bean 创建的三个阶段可以总结为:
| 阶段 | 方法 | 做了什么 | 回调 / 扩展点 |
|---|---|---|---|
| 实例化 | createBeanInstance() | 反射/工厂方法/CGLIB 创建裸对象 | InstantiationAwareBPP.postProcessBeforeInstantiation() |
| 属性填充 | populateBean() | 注入依赖(@Autowired, @Value) | InstantiationAwareBPP.postProcessAfterInstantiation() |
| 初始化 | initializeBean() | Aware 回调 + BPP + init 方法 | BeanPostProcessor(AOP 代理在这里生成) |
BeanPostProcessor.postProcessAfterInitialization() 中,由 AbstractAutoProxyCreator 判断是否需要代理,如果需要则返回代理对象替代原始 Bean。三级缓存:循环依赖的解决思路(预告)
Spring 用三级缓存解决单例 Bean 的循环依赖。三级缓存定义在 DefaultSingletonBeanRegistry 中:
// 一级缓存:完整的 Bean 实例(已初始化完毕)
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
// 二级缓存:早期 Bean 实例(已实例化,未填充属性)
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
// 三级缓存:Bean 工厂(ObjectFactory,用于生成早期引用)
private final Map<String, ObjectFactory<?>> singletonFactories
= new HashMap<>(16);
解决循环依赖的核心流程(以 A→B→A 为例):
- 创建 A:实例化 A(裸对象)→ 将 A 的 ObjectFactory 放入三级缓存
- 填充 A:发现依赖 B → 触发创建 B
- 创建 B:实例化 B(裸对象)→ 将 B 的 ObjectFactory 放入三级缓存
- 填充 B:发现依赖 A → 从三级缓存取 A 的 ObjectFactory → 生成 A 的早期引用 → 放入二级缓存,删除三级缓存
- B 完成初始化 → 放入一级缓存
- A 获得 B → 继续填充属性 → A 完成初始化 → 放入一级缓存
ObjectFactory(Lambda 表达式)。它的作用是在需要早期引用时,通过 getEarlyBeanReference() 提前触发 AOP 代理。如果没有 AOP,两级缓存就够了;正是为了延迟代理对象的创建(只在真正被循环依赖时才创建代理),才需要第三级。getSingleton() = L1 有就返回 → L2 有就返回 → L3 有就调用 factory.getObject() 放入 L2 并删除 L3 → 返回
完整的三级缓存源码拆解、构造器注入为何无法解决循环依赖、Spring Boot 2.6+ 默认禁止循环依赖的原因,将在「Spring 循环依赖与三级缓存」专文中详细展开。
总结:关键接口速查 + 面试回答模板
| 接口 / 类 | 职责 | 关键方法 |
|---|---|---|
BeanFactory | 容器根接口,定义 getBean / containsBean | getBean(), isSingleton() |
ApplicationContext | 全功能容器,集成 i18n / 事件 / AOP | publishEvent(), getMessage() |
BeanDefinition | Bean 的元数据描述 | getBeanClassName(), getScope() |
BeanDefinitionRegistry | BeanDefinition 的注册中心 | registerBeanDefinition() |
BeanPostProcessor | Bean 初始化前后的拦截钩子 | postProcessBeforeInitialization(), postProcessAfterInitialization() |
BeanFactoryPostProcessor | BeanFactory 级别的处理器(修改 BeanDefinition) | postProcessBeanFactory() |
DefaultSingletonBeanRegistry | 单例 Bean 的三级缓存管理 | getSingleton(), addSingleton() |
AbstractApplicationContext | 容器启动流程的编排者 | refresh()(十二步) |
- 概念:IoC 是设计思想,DI 是实现方式。Spring 容器负责对象的创建、装配和生命周期管理。
- 接口:BeanFactory 是最小容器(懒加载),ApplicationContext 是全功能容器(预创建单例、i18n、事件、AOP)。日常用的都是 ApplicationContext。
- 启动:核心方法是
refresh(),十二步编排了整个启动流程——先解析 BeanDefinition,再注册后处理器,最后实例化所有单例 Bean。 - Bean 创建:getBean → createBean → doCreateBean,分三阶段:实例化 → 属性填充 → 初始化(含 AOP 代理)。
- 循环依赖:通过三级缓存解决——一级存完整 Bean,二级存早期引用,三级存 ObjectFactory(为 AOP 代理延迟创建)。