如果说「IoC 原理」是认识 Spring 的第一课,那么「容器实现」才是真正拉开普通开发者与资深工程师差距的分水岭。本文从源码视角还原 getBean 的完整调用链、Bean 生命周期回调的精确时序、循环依赖三级缓存的每一步细节,并系统梳理六大自定义扩展点,帮助你在生产环境中精准定位问题、写出可扩展的框架级代码。
前置基础可先阅读 Spring IoC 容器与依赖注入原理深度剖析 与 Spring Boot 核心原理与自动配置。
1. IoC 容器内核:BeanFactory 与 ApplicationContext 体系
1.1 BeanFactory 接口族谱
BeanFactory 是整个 IoC 容器的根接口,定义了对 Bean 的获取、类型查询、是否包含等最基本能力。真正的实现体系远比「一个类」复杂:
BeanFactory(根接口)
├── HierarchicalBeanFactory ── 父子容器
│ └── ConfigurableBeanFactory ── parent / 类加载器 / 类型转换
│ └── DefaultListableBeanFactory ← 核心实现(beanDefinitionMap、singletonObjects)
└── ListableBeanFactory ── 按类型/注解列举 Bean
└── ApplicationContext 体系 ── 继承全部子接口
| 接口/类 | 核心职责 |
|---|---|
BeanFactory | 最基本的 getBean 语义,延迟实例化 |
ListableBeanFactory | 枚举 Bean、按注解/类型查询 |
HierarchicalBeanFactory | 父子容器,子容器优先查找 |
AutowireCapableBeanFactory | 暴露 createBean/autowireBean 给框架集成 |
DefaultListableBeanFactory | 默认实现,持有全部 Bean 定义与单例缓存 |
ApplicationContext | 完整的企业级容器,具备全部子接口能力 |
1.2 ApplicationContext 的六大附加能力
ApplicationContext 继承 BeanFactory、ListableBeanFactory 等五个接口,叠加了企业级容器所需的一切:
| 能力 | 实现接口 | 典型场景 |
|---|---|---|
| 国际化 | MessageSource | MessageSource.getMessage(code, args, locale) |
| 资源加载 | ResourcePatternResolver | classpath*: 通配符、@PropertySource |
| 事件发布 | ApplicationEventPublisher | publishEvent() + @EventListener |
| 环境抽象 | EnvironmentCapable | getEnvironment() 读取 profile / 属性 |
| AOP 自动织入 | AutowireCapableBeanFactory | @EnableAspectJAutoProxy 自动注册 |
| 自动后处理 | 内置多个 BeanPostProcessor | CommonAnnotationBeanPostProcessor 等 |
Spring Boot 中默认的容器实例是 AnnotationConfigApplicationContext(非 Web)或 AnnotationConfigServletWebServerApplicationContext(Web),它们最终都委托给内部的 DefaultListableBeanFactory。
1.3 getBean 完整调用链源码
getBean 是容器最核心的入口,我们沿着调用链看每一步做了什么:
getBean(name)
└─ doGetBean(name, requiredType, args, false)
├─ ① transformedBeanName 转换规范名称(去 &)
├─ ② getSingleton(beanName) 先查三级缓存 → 命中即返回
├─ ③ 父容器兜底查找
├─ ④ getMergedLocalBeanDefinition 合并 BeanDefinition
├─ ⑤ 处理 dependsOn 依赖(先实例化依赖 Bean)
├─ ⑥ 按作用域分支:
│ ├─ singleton → getSingleton(name, singletonFactory) ← 核心
│ │ └─ createBean → doCreateBean(见第 3 节)
│ ├─ prototype → createBean 直接返回(不进缓存)
│ └─ request/session → RequestScope/SessionScope
└─ ⑦ TypeConverter 类型适配 requiredType
// AbstractBeanFactory.java(简化)
protected <T> T doGetBean(...) {
String beanName = transformedBeanName(name);
Object sharedInstance = getSingleton(beanName); // ② 三级缓存
if (sharedInstance != null && args == null) {
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
} else {
// 父容器 / 合并定义 / dependsOn / 作用域创建...
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
return createBean(beanName, mbd, args); // ⑥ 核心创建
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
}
return adaptBeanInstance(name, bean, requiredType); // ⑦ 类型适配
}
理解这条链路,就理解了「先查缓存 → 再创建 → 再适配」的三段式容器行为。
2. BeanDefinition 的注册与合并
2.1 BeanDefinition 的结构
BeanDefinition 是 Bean 的「生产图纸」,容器不直接操作对象,而是先解析出 BeanDefinition:
// BeanDefinition 关键属性
class GenericBeanDefinition {
String scope = "singleton"; // 作用域
boolean lazyInit; // 是否懒加载
String factoryBeanName; // factory-bean(实例工厂)
String factoryMethodName; // factory-method
boolean primary; // @Primary 优先注入
String initMethodName; // init-method
String destroyMethodName; // destroy-method
String[] dependsOn; // 显式依赖
boolean autowireCandidate; // 是否参与自动装配
ResolvableType resolvableType; // 泛型类型
boolean synthetic; // 框架内部生成(AOP、事件监听器)
}
2.2 注册的两个入口
// 入口一:@Component 扫描 → 解析候选组件生成 ScannedGenericBeanDefinition
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(registry);
scanner.scan("com.example.service");
// 入口二:@Bean 方法 → ConfigurationClassPostProcessor 在刷新早期解析,
// 生成 BeanDefinition,factoryMethodName 指向配置类方法
3. getBean → doCreateBean:对象创建全链路
createBean 最终落到 AbstractAutowireCapableBeanFactory.createBean 与 doCreateBean。这是整个生命周期的心脏:
3.1 实例化前短路:resolveBeforeInstantiation
// AbstractAutowireCapableBeanFactory.createBean(简化)
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) {
Object bean = resolveBeforeInstantiation(beanName, mbd); // ① 短路机会
if (bean != null) {
return bean; // 直接返回代理或替换 Bean,跳过后续
}
return doCreateBean(beanName, mbd, args); // ② 正式创建
}
resolveBeforeInstantiation 依次调用所有 InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation,并执行 postProcessAfterInitialization。AOP 场景下 AbstractAutoProxyCreator 在这里就为适配器 Bean 创建代理。
3.2 实例化策略:InstantiationStrategy
doCreateBean 通过 createBeanInstance 完成对象实例化,底层使用 InstantiationStrategy:
| 场景 | 策略 | 说明 |
|---|---|---|
| 无参构造 + 非代理 | SimpleInstantiationStrategy | 反射 clazz.getDeclaredConstructor().newInstance() |
| 需要子类代理 | CglibSubclassingInstantiationStrategy | 生成子类(@Lookup、@Configuration 类、proxyBeanMethods) |
@Bean 工厂方法 | 反射调用工厂方法 | 参数通过 AutowireCandidateResolver 解析 |
FactoryBean | 先创建 FactoryBean 自身 | 再 getObject() 产出实际 Bean |
// ConstructorResolver 依次尝试:
// ① autowireConstructor(@Autowired 构造器)→ ② 主构造器(Spring 4.3+)→ ③ 默认无参构造
Constructor<?> ctor = resolveAutowiredCandidate(...);
3.3 属性填充:populateBean
// doCreateBean 关键片段(简化)
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, Object[] args) {
BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args); // ① 实例化
Object bean = instanceWrapper.getWrappedInstance();
if (mbd.isSingleton()) {
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); // ② 三级缓存入口
}
populateBean(beanName, mbd, instanceWrapper); // ③ 属性填充(依赖注入发生地)
Object exposedObject = initializeBean(beanName, bean, mbd); // ④ 初始化回调
return exposedObject;
}
populateBean 的注入次序是:InstantiationAwareBeanPostProcessor 属性后处理 → byType/byName 自动装配 → @Autowired/@Value/@Resource 注解注入。@Autowired 由 AutowiredAnnotationBeanPostProcessor.postProcessProperties 完成,它通过 InjectionMetadata 一次性解析类上的注入点。
3.4 初始化:initializeBean
initializeBean 是生命周期回调的集中地,顺序严格固定:
protected Object initializeBean(String beanName, Object bean, RootBeanDefinition mbd) {
invokeAwareMethods(beanName, bean); // ① Aware(BeanName/ClassLoader/BeanFactory)
Object wrapped = applyBeanPostProcessorsBeforeInitialization(bean, beanName); // ② BeforeInit
invokeInitMethods(beanName, wrapped, mbd); // ③ InitializingBean + init-method
return applyBeanPostProcessorsAfterInitialization(wrapped, beanName); // ④ AfterInit(AOP)
}
陷阱提示:invokeAwareMethods 只处理三个最基础的 Aware;其余如 ApplicationContextAware、ApplicationEventPublisherAware 由 ApplicationContextAwareProcessor(一个内置的 BeanPostProcessor)在「② 初始化前」阶段回调。这也是为什么 @PostConstruct 依赖 ApplicationContextAware 注入的值时要注意时序。
4. 生命周期回调完整时序
4.1 全景时序图
Bean 生命周期(单例,含全部回调):
① InstantiationAwareBPP.postProcessBeforeInstantiation(可短路)
② 构造器 / 工厂方法(createBeanInstance)
③ addSingletonFactory(三级缓存提前暴露)
④ populateBean → InstantiationAwareBPP.postProcessProperties(@Autowired 注入)
⑤ ApplicationContextAwareProcessor(ApplicationContextAware 等)
⑥ BeanPostProcessor.postProcessBeforeInitialization → @PostConstruct
⑦ InitializingBean.afterPropertiesSet() ⑧ 自定义 init-method
⑨ BeanPostProcessor.postProcessAfterInitialization(AOP 代理)
⑩ SmartInitializingSingleton(全部单例创建完成后)
使用中...
销毁:@PreDestroy → DisposableBean.destroy() → destroy-method
4.2 多个 BeanPostProcessor 的链式顺序
Spring 保证 postProcessBeforeInitialization 和 postProcessAfterInitialization 按 Ordered 顺序执行(order 小的先执行),但前后两个阶段方向相反:
| BeanPostProcessor | order | Before 阶段 | After 阶段 |
|---|---|---|---|
ApplicationContextAwareProcessor | — | 注入 Aware | — |
CommonAnnotationBeanPostProcessor | Integer.MAX_VALUE | 执行 @PostConstruct | 注册 @PreDestroy |
AutowiredAnnotationBeanPostProcessor | — | 解析 @Autowired(此时属性已注入) | — |
AbstractAutoProxyCreator | Ordered.HIGHEST_PRECEDENCE | 提前暴露代理判断 | 创建代理(AOP) |
@Configuration
public class OrderedProcessors {
@Bean
public static BeanPostProcessor firstProcessor() {
return new MyProcessor(); // 实现 Ordered.getOrder() 返回 0
}
@Bean
public static BeanPostProcessor secondProcessor() {
return new MyProcessor2(); // getOrder() 返回 10
}
}
// 执行顺序:order 小的 before 先执行,after 反向:小 order 的 after 后执行
4.3 预实例化收尾:SmartInitializingSingleton
ApplicationContext 默认对所有非懒加载单例预实例化,完成后回调 SmartInitializingSingleton.afterSingletonsInstantiated()——这是「所有业务 Bean 已就绪」的可靠信号,适合做启动预热与配置校验:
@Component
public class CacheWarmer implements SmartInitializingSingleton {
@Override
public void afterSingletonsInstantiated() {
productService.preloadHotProducts(); // 此时可安全依赖任意 Bean
}
}
5. 循环依赖三级缓存源码深挖
5.1 三级缓存结构
循环依赖解决依赖 DefaultSingletonBeanRegistry 的三级缓存,本质是一个「先给引用,后补完整」的两阶段提交:
singletonObjects 一级:Map<String, Object> 完整 Bean,随时可用
earlySingletonObjects 二级:Map<String, Object> 提前暴露的「原始」引用
singletonFactories 三级:Map<String, ObjectFactory<?>> 可生成提前引用的工厂
5.2 getSingleton:从三级到二级的晋升
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName); // 一级:完整 Bean
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
singletonObject = this.earlySingletonObjects.get(beanName); // 二级:早期引用
if (singletonObject == null && allowEarlyReference) {
synchronized (this.singletonObjects) {
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject(); // ③ 调工厂产出
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName); // 晋升:三级 → 二级
}
}
}
}
}
}
return singletonObject;
}
5.3 为什么需要三级而不是两级
答案在于代理:如果目标 Bean 最终会被 AOP 代理,那么提前暴露的必须是代理对象(否则注入的原始对象与最终代理不一致)。但创建代理需要知道 Bean 是否被 AOP 标记,检测发生在实例化之后。三级缓存的 ObjectFactory 把「决策延后」到被依赖方真正访问的那一刻:
// doCreateBean 实例化后立即调用 addSingletonFactory 放入三级
this.singletonFactories.put(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
// 工厂的核心:getEarlyBeanReference
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
// SmartInstantiationAwareBeanPostProcessor.getEarlyBeanReference
exposedObject = bp.getEarlyBeanReference(exposedObject, beanName); // 生成提前代理
}
}
return exposedObject;
}
5.4 代理场景的完整时间线
A、B 循环依赖,且 B 需要 AOP 代理:
1. 创建 A → addSingletonFactory(A, factory_A)
2. 填充 A 需要 B → getBean(B) → 创建 B → addSingletonFactory(B, factory_B)
3. 填充 B 需要 A → getSingleton(A):
一级无 → 二级无 → 三级 factory_A.getObject()
→ getEarlyBeanReference 生成代理 A' → A' 入二级 → B 注入 A'
4. B 初始化完成入一级;回到 A 填充注入 B
5. A initializeBean:postProcessAfterInitialization 发现已提前暴露
→ 若 exposedObject == 原始对象,返回「提前代理 A'」;否则校验一致性
6. A(代理)放入一级
5.5 无法解决的循环依赖场景
| 场景 | 原因 | 解决 |
|---|---|---|
| 构造器注入循环 | 实例化 A 需要 B,B 实例化需要 A,此时 A 还没进三级缓存 | @Lazy 注入代理 / 重构 |
prototype 作用域循环 | prototype 不缓存、无三级缓存参与 | 禁止相互注入 / 改为单例 |
@Async 循环 | 异步代理需要提前创建,但 AsyncAnnotationBeanPostProcessor 不属于 SmartInstantiation 族 | 拆分 Bean / 单独配置 |
@Transactional 自调用 | 并非循环依赖问题,而是自调用不经过代理 | 自注入 / AopContext / 拆分 |
// Spring Boot 2.6+ 默认禁止循环依赖:启动即报错
// spring.main.allow-circular-references=true 可放开(不推荐,只是给存量系统兜底)
6. 自定义扩展点全景
6.1 六大扩展点对比
| 扩展点 | 触达时机 | 能做什么 | 典型框架 |
|---|---|---|---|
BeanDefinitionRegistryPostProcessor | 容器刷新早期 | 注册/修改 BeanDefinition | MyBatis MapperScannerConfigurer |
BeanFactoryPostProcessor | BeanDefinition 已注册,Bean 未实例化 | 修改 BeanDefinition 属性 | 属性占位符替换 |
BeanPostProcessor | 每个 Bean 初始化前后 | 包装/替换 Bean 实例 | AOP、@Autowired 解析 |
InstantiationAwareBeanPostProcessor | 实例化前后 | 短路实例化、拦截属性填充 | 自定义依赖注入 |
FactoryBean | 创建时 | 隐藏复杂创建过程 | MyBatis MapperFactoryBean |
ImportBeanDefinitionRegistrar | 处理 @Import 时 | 编程式注册多个 BeanDefinition | Spring 内部、第三方 starter |
6.2 BeanFactoryPostProcessor vs BeanDefinitionRegistryPostProcessor
两者都在容器刷新阶段调用,但后者更早、能注册新定义:
@Component
public class MyRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
// 阶段一:注册新 BeanDefinition(此时尚无 Bean 被实例化)
AbstractBeanDefinition bd = BeanDefinitionBuilder
.genericBeanDefinition(MyService.class).setInitMethodName("init").getBeanDefinition();
registry.registerBeanDefinition("myService", bd);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 阶段二:修改既有 BeanDefinition 属性
beanFactory.getBeanDefinition("myService").getPropertyValues().add("timeout", 3000);
}
}
6.3 InstantiationAwareBeanPostProcessor:AOP 织入窗口
public class CustomInstantiationAwareBPP implements InstantiationAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
if (beanName.equals("specialBean")) {
return new SpecialBeanProxy(); // 直接替换,跳过后续流程
}
return null; // null → 走正常流程
}
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) {
return !beanName.equals("noAutowired"); // false → 跳过属性填充
}
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
return pvs; // 属性填充前自定义处理
}
}
6.4 FactoryBean:隐藏复杂创建
@Component
public class ComplexClientFactoryBean implements FactoryBean<ComplexClient> {
@Override
public ComplexClient getObject() {
// 复杂构建逻辑:连接池、重试、超时、校验
return ComplexClient.builder().connectionTimeout(5000).poolSize(32).build();
}
@Override
public Class<?> getObjectType() { return ComplexClient.class; }
@Override
public boolean isSingleton() { return true; }
}
// 注入 ComplexClient 即可,容器自动调用 getObject()
// 获取 FactoryBean 本身:getBean("&complexClientFactoryBean")
6.5 SmartLifecycle:启动顺序控制
@Component
public class MessageConsumer implements SmartLifecycle {
private volatile boolean running = false;
@Override
public void start() { running = true; } // 容器启动阶段:启动 MQ 消费者
@Override
public void stop() { running = false; } // 容器关闭阶段:优雅下线
@Override
public boolean isRunning() { return running; }
@Override
public int getPhase() { return Integer.MAX_VALUE; }
// phase 越大越晚启动、越早停止:依赖方用小 phase,被依赖方用大 phase
}
6.6 ImportBeanDefinitionRegistrar
public class MyRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setBeanClass(Router.class);
bd.getPropertyValues().add("routes", discoverRoutes(importingClassMetadata));
registry.registerBeanDefinition("router", bd); // 编程式注册
}
}
@Configuration
@Import(MyRegistrar.class) // 组合注解 @EnableXxx 的惯用实现方式
public class AppConfig {}
7. 生产实践:作用域代理、自注入与常见坑
7.1 作用域代理原理
@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS) 的 Bean 注入到单例 Bean 时,注入的是代理对象,代理在每次调用时委托给当前作用域内的真实实例:
@Component
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class RequestContextHolder { ... }
@Service
public class OrderFacade {
private final RequestContextHolder ctx; // 注入的是代理
// 每次调用 ctx 的方法,代理解析当前 HTTP 请求对应的真实实例
}
代理由 Scope 接口的 get/remove + 目标 Bean 类型生成(CGLIB 子类或 JDK 接口代理)。代价:每次方法调用多一次代理转发,且 this 内部自调用仍指向代理,字段访问不会被拦截。
7.2 自引用注入
@Service
public class UserService {
@Autowired
private UserService self; // 自注入:让方法经过代理
@Transactional
public void createUser(User u) { ... }
public void createUserBatch(List<User> users) {
users.forEach(u -> self.createUser(u)); // 通过 self 调用才能触发事务代理
}
}
7.3 常见坑清单
| 坑 | 现象 | 根因与对策 |
|---|---|---|
| 自调用事务失效 | this.method() 不生效 | 事务基于代理,必须注入自身代理调用 |
@PostConstruct 访问代理字段 | 拿到的是 null | 代理字段未注入,应通过方法注入而非字段访问 |
| 懒加载 Bean 提前实例化 | 启动变慢、日志出现非预期初始化 | @Lazy 的 Bean 被 SmartInitializingSingleton 或启动探针触碰 |
| 循环依赖告警 | 启动日志 WARN | Spring Boot 2.6+ 默认报错,重构而非放开关 |
| 构造器注入两个同类型 | NoUniqueBeanDefinitionException | 加 @Primary 或 @Qualifier |
8. 总结
| 主题 | 核心要点 |
|---|---|
| 容器体系 | BeanFactory 是根,ApplicationContext 叠加事件/国际化/AOP |
| 创建链路 | getBean → getSingleton → createBean → doCreateBean → initializeBean |
| 生命周期 | 实例化 → 属性填充 → Aware → BeforeInit → InitializingBean → AfterInit |
| 三级缓存 | singletonObjects / earlySingletonObjects / singletonFactories |
| 代理提前暴露 | getEarlyBeanReference 保证注入的是最终代理 |
| 扩展点 | 六大扩展点按容器刷新阶段选择 |
| 生产坑 | 自调用、作用域代理、循环依赖、懒加载提前触碰 |
IoC 容器是 Spring 最精密的机械。掌握 getBean 的调用链、生命周期的精确时序与三级缓存的每一步,你就拥有了诊断大多数 Spring 疑难杂症的底层能力;再配合六大扩展点,就能写出 MyBatis、Seata 这类框架级的集成代码。
延伸阅读
- Spring AOP 原理剖析与 AspectJ 企业级实战 — 代理的创建时机与本篇第 5 节呼应
- Spring Boot 核心原理与自动配置 — 容器刷新流程的上层视角
- Bean Validation 与 Hibernate Validator 数据校验精要 — 校验器注入的生命周期细节
- 微服务接口设计与治理 — 多个 Bean 注入集合的工程实践
- 系统架构设计 — 依赖倒置原则在架构层面的落地
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。