本文从理论溯源出发,经 Martin Fowler 2004 年的经典定义,逐层深入 Spring IoC 的单 Bean 微观视角:BeanDefinition 加载、9 阶段生命周期源码链路、@Autowired vs @Resource 注入机制,以及 @Configuration Full/Lite 模式差异,是容器启动流程的配套微观篇。
目录
| 章节 | 说明 |
|---|---|
| 理论基础 | IoC 本质、Fowler 的 DI 定义、Service Locator vs DI |
| IoC 容器体系 | BeanFactory vs ApplicationContext,层次结构 |
| BeanDefinition | Bean 的"配方",加载方式与核心字段 |
| Bean 生命周期 | 9 阶段完整流程与源码路径 |
| 关键扩展点 | BeanPostProcessor 家族与执行时机 |
| 注入机制 | @Autowired vs @Resource vs 构造器注入 |
| 配置类模式 | @Configuration Full/Lite 模式与 CGLIB 代理 |
| 面试常见题 | 高频追问与答题要点 |
理论基础
IoC 的本质
控制反转(Inversion of Control) 是一个设计原则,核心是把"谁来负责创建依赖对象"这件事的控制权,从应用代码转移到外部框架。
传统方式,对象自己负责获取依赖:
// 主动查找:控制权在 OrderService 自己手里
public class OrderService {
private InventoryService inventory = new InventoryService(); // 直接 new
private UserService user = ServiceLocator.get(UserService.class); // 主动查找
}
IoC 之后,依赖由外部注入:
// 被动接收:控制权交给容器
public class OrderService {
private final InventoryService inventory;
private final UserService user;
public OrderService(InventoryService inventory, UserService user) {
this.inventory = inventory; // 由容器注入
this.user = user;
}
}
好莱坞原则(Hollywood Principle):"Don't call us, we'll call you." 对象不主动寻找依赖,等容器来调用。
Fowler 2004:IoC → Dependency Injection
2004 年,Martin Fowler 在《Inversion of Control Containers and the Dependency Injection pattern》中指出:IoC 太泛化,几乎任何框架都涉及控制反转,需要更精确的术语——依赖注入(Dependency Injection)。
Fowler 定义了三种注入形式:
| 注入类型 | 说明 | Spring 支持 |
|---|---|---|
| 构造器注入(Constructor Injection) | 依赖通过构造器参数传入 | ✅ 推荐 |
| Setter 注入(Setter Injection) | 依赖通过 setter 方法注入 | ✅ |
| 接口注入(Interface Injection) | 组件实现注入接口,容器调用 | ⚠️ Spring 不支持(过于侵入) |
Spring 在此基础上延伸,将字段注入(Field Injection,直接注入成员变量)作为第四种方式,但 Fowler 原文没有提及,也是争议最大的一种。
Service Locator vs Dependency Injection
Fowler 在同篇文章中对比了两种模式:
| Service Locator | Dependency Injection | |
|---|---|---|
| 依赖获取方式 | 主动调用 Locator.get(X.class) |
被动接收(构造器/setter) |
| 对容器的感知 | 代码中显式依赖 Locator | 代码完全不感知容器存在 |
| 可测试性 | 测试需初始化 Locator | 测试直接传入 mock 对象 |
| 典型实现 | JNDI、ServiceLocator 模式 |
Spring DI、Guice |
Fowler 的结论:两者都能实现服务配置与使用的分离,DI 的优势在于更彻底地消除应用代码对容器的感知,可测试性更强。
Spring 早期(1.x)同时支持 Service Locator 风格(BeanFactory.getBean()),但官方明确推荐 DI 风格,getBean() 仅用于容器入口点。
IoC 容器体系
BeanFactory vs ApplicationContext
| 维度 | BeanFactory |
ApplicationContext |
|---|---|---|
| 定位 | 最基础的容器接口,只管 Bean 的获取 | 企业级容器,扩展了 BeanFactory |
| 加载时机 | 懒加载(getBean 时才实例化) |
启动时预加载所有单例 Bean |
| 额外能力 | ❌ | 国际化、事件发布、资源加载、ApplicationListener |
| 典型实现 | DefaultListableBeanFactory |
AnnotationConfigApplicationContext、SpringApplication |
ApplicationContext持有一个DefaultListableBeanFactory作为内部委托,所有 Bean 的注册和查找最终都走它。
继承关系(简化)
BeanFactory
└── HierarchicalBeanFactory(支持父容器)
└── ConfigurableBeanFactory
└── ConfigurableListableBeanFactory
└── DefaultListableBeanFactory ← 核心实现
ApplicationContext
└── ConfigurableApplicationContext
└── AbstractApplicationContext
└── AnnotationConfigApplicationContext(注解驱动)
└── ClassPathXmlApplicationContext(XML 驱动)
BeanDefinition
是什么
BeanDefinition 是 Bean 的"配方"——Spring 先把所有配置信息解析成 BeanDefinition 注册到 BeanDefinitionRegistry,实例化阶段再按配方创建对象。
配置来源 解析器 注册目标
──────────────────────────────────────────────────────────────
@Component 扫描 → ClassPathBeanDefinitionScanner → BeanDefinitionRegistry
@Configuration → ConfigurationClassPostProcessor → BeanDefinitionRegistry
XML → XmlBeanDefinitionReader → BeanDefinitionRegistry
核心字段
// AbstractBeanDefinition 核心字段
String beanClassName; // Bean 的全限定类名
String scope; // singleton / prototype / request ...
boolean lazyInit; // 是否懒加载
String[] dependsOn; // depends-on 依赖
ConstructorArgumentValues constructorArgumentValues; // 构造器参数
MutablePropertyValues propertyValues; // 属性注入值
String initMethodName; // init-method
String destroyMethodName; // destroy-method
boolean primary; // @Primary
boolean abstractFlag; // 是否抽象(不实例化)
BeanDefinition 合并
子 BeanDefinition 会继承父 BeanDefinition 的属性,通过 getMergedLocalBeanDefinition() 合并为 RootBeanDefinition 后才用于实例化。这是 XML 时代 <bean parent="..."> 的配方继承机制。
Bean 生命周期
完整流程(9 阶段)
源码主干路径
// AbstractBeanFactory#doGetBean(精简)
protected <T> T doGetBean(String name, ...) {
// 1. 先查单例池(三级缓存)
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null) {
return getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
// 2. 合并 BeanDefinition
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// 3. 处理 depends-on
// 4. 创建 Bean
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> createBean(beanName, mbd, args));
}
return (T) getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// AbstractAutowireCapableBeanFactory#doCreateBean(精简)
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, Object[] args) {
// ④ 实例化
BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args);
Object bean = instanceWrapper.getWrappedInstance();
// ⑤ 提前暴露(解决循环依赖)
if (earlySingletonExposure) {
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// ⑥ 属性注入
populateBean(beanName, mbd, instanceWrapper);
// ⑦ 初始化
Object exposedObject = initializeBean(beanName, bean, mbd);
return exposedObject;
}
initializeBean 展开
// AbstractAutowireCapableBeanFactory#initializeBean(精简)
protected Object initializeBean(String beanName, Object bean, RootBeanDefinition mbd) {
// Aware 回调
invokeAwareMethods(beanName, bean);
// BeanPostProcessor before(@PostConstruct 由 CommonAnnotationBeanPostProcessor 处理)
Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
// init-method(afterPropertiesSet → init-method)
invokeInitMethods(beanName, wrappedBean, mbd);
// BeanPostProcessor after(AbstractAutoProxyCreator 在此创建 AOP 代理)
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
return wrappedBean;
}
初始化方法执行顺序
@PostConstruct ← CommonAnnotationBeanPostProcessor 处理(before 阶段)
afterPropertiesSet() ← InitializingBean 接口
init-method ← XML / @Bean(initMethod="...") 指定
销毁顺序与之镜像:@PreDestroy → destroy() → destroy-method
构造器推断
createBeanInstance() 调用 determineConstructorsFromBeanPostProcessors()(实际由 AutowiredAnnotationBeanPostProcessor 处理),推断规则:
| 情况 | 选择策略 |
|---|---|
| 只有一个构造器 | 直接使用 |
有 @Autowired 构造器 |
使用被标注的构造器 |
| 有无参 + 有参构造器 | 优先无参(除非有 @Autowired) |
@Autowired(required=false) 多个 |
找最贪心(参数最多且都能满足)的构造器 |
关键扩展点
BeanPostProcessor 家族
BeanPostProcessor
├── postProcessBeforeInitialization ← 初始化前(@PostConstruct 在此)
└── postProcessAfterInitialization ← 初始化后(AOP 代理在此)
InstantiationAwareBeanPostProcessor(继承 BPP)
├── postProcessBeforeInstantiation ← 实例化前(可短路)
├── postProcessAfterInstantiation ← 实例化后(可跳过注入)
└── postProcessProperties ← 属性注入(@Autowired 在此)
DestructionAwareBeanPostProcessor(继承 BPP)
└── postProcessBeforeDestruction ← 销毁前(@PreDestroy 在此)
常见 BeanPostProcessor 实现
| 实现类 | 处理内容 |
|---|---|
AutowiredAnnotationBeanPostProcessor |
@Autowired / @Value / @Inject |
CommonAnnotationBeanPostProcessor |
@PostConstruct / @PreDestroy / @Resource |
AbstractAutoProxyCreator |
AOP 代理创建(postProcessAfterInitialization) |
ApplicationContextAwareProcessor |
ApplicationContextAware 等 Aware 回调 |
PersistenceAnnotationBeanPostProcessor |
JPA @PersistenceContext |
BeanFactoryPostProcessor vs BeanPostProcessor
BeanFactoryPostProcessor |
BeanPostProcessor |
|
|---|---|---|
| 作用对象 | BeanDefinition(配方) |
Bean 实例(成品) |
| 执行时机 | 所有 BeanDefinition 注册完成后、Bean 实例化之前 | 每个 Bean 实例化/初始化时 |
| 典型实现 | PropertySourcesPlaceholderConfigurer(解析 ${}) |
AutowiredAnnotationBeanPostProcessor |
BeanDefinitionRegistryPostProcessor继承BeanFactoryPostProcessor,还能动态注册新的 BeanDefinition(ConfigurationClassPostProcessor是其典型实现)。
注入机制
@Autowired vs @Resource
| 维度 | @Autowired |
@Resource |
|---|---|---|
| 来源 | Spring 原生 | JSR-250(Java 标准) |
| 查找顺序 | 先 byType,多个则 byName(配合 @Qualifier) |
先 byName,找不到则 byType |
| 处理器 | AutowiredAnnotationBeanPostProcessor |
CommonAnnotationBeanPostProcessor |
| required | 支持 required=false |
不支持,找不到直接报错 |
| 可用位置 | 字段 / 方法 / 构造器 / 参数 | 字段 / setter 方法 |
@Autowired 源码路径
// AutowiredAnnotationBeanPostProcessor#postProcessProperties
// → findAutowiringMetadata(扫描 @Autowired 字段/方法)
// → InjectionMetadata#inject
// → AutowiredFieldElement#inject(字段注入)
// → beanFactory.resolveDependency(descriptor, beanName, ...)
// → DefaultListableBeanFactory#doResolveDependency
// → findAutowireCandidates(byType 查找候选)
// → determineAutowireCandidate(byName 决胜 或 @Primary/@Priority)
三种注入方式对比
| 方式 | 优点 | 缺点 |
|---|---|---|
字段注入(@Autowired 字段) |
代码简洁 | 无法 final,单元测试难以注入 mock |
| Setter 注入 | 可选依赖,可重新注入 | 无法保证注入完整性 |
| 构造器注入(推荐) | 依赖不可变(final),单元测试友好,能暴露循环依赖 | 参数多时代码冗长 |
Spring 官方推荐构造器注入;
@Autowired作用于唯一构造器时可省略注解(Spring 4.3+)。
配置类模式
Full 模式(@Configuration)
@Configuration 类会被 CGLIB 代理,代理逻辑拦截所有 @Bean 方法调用:
@Configuration
public class AppConfig {
@Bean
public ServiceA serviceA() {
return new ServiceA(serviceB()); // 多次调用 serviceB() 返回同一实例
}
@Bean
public ServiceB serviceB() {
return new ServiceB();
}
}
serviceA() 内调用 serviceB() 时,CGLIB 代理拦截,先查容器单例池,找到则直接返回,不会创建新对象。
Lite 模式(@Component / @ComponentScan)
@Component 类上的 @Bean 方法不走 CGLIB 代理:
@Component
public class AppConfig {
@Bean
public ServiceA serviceA() {
return new ServiceA(serviceB()); // ⚠️ 直接 new ServiceB(),每次新建
}
@Bean
public ServiceB serviceB() {
return new ServiceB();
}
}
对比
Full 模式(@Configuration) |
Lite 模式(@Component) |
|
|---|---|---|
| CGLIB 代理 | ✅ | ❌ |
@Bean 方法互调 |
返回容器中的单例 | 每次新建对象 |
| 启动性能 | 略慢(CGLIB 生成代理类) | 略快 |
| 适用场景 | 有 @Bean 方法互相依赖时 |
简单场景,或追求轻量启动 |
@SpringBootApplication内含@SpringBootConfiguration,后者是@Configuration的派生注解,因此 Spring Boot 主类是 Full 模式。
proxyBeanMethods=false
Spring Boot 2.2+ 引入,@Configuration(proxyBeanMethods = false) 可手动切换为 Lite 模式,常用于自动配置类提升启动速度:
@Configuration(proxyBeanMethods = false) // 大量 Spring Boot AutoConfiguration 使用此模式
@ConditionalOnClass(DataSource.class)
public class DataSourceAutoConfiguration { ... }
面试常见题
Q1:Bean 生命周期说一下
实例化(构造器)→ 属性注入(@Autowired)→ Aware 回调 → @PostConstruct → afterPropertiesSet → init-method → AOP 代理(BPP after)→ 使用 → @PreDestroy → destroy → destroy-method
Q2:@PostConstruct 和 afterPropertiesSet 哪个先?
@PostConstruct 先。两者都在 initializeBean() 中触发,@PostConstruct 由 CommonAnnotationBeanPostProcessor 在 postProcessBeforeInitialization 阶段处理,而 afterPropertiesSet 在随后的 invokeInitMethods 中调用。
Q3:@Configuration 加不加有什么区别?
加了是 Full 模式(CGLIB 代理),@Bean 方法互调返回同一实例;不加(或 proxyBeanMethods=false)是 Lite 模式,每次调用 @Bean 方法都 new 新对象。
Q4:BeanFactory 和 FactoryBean 的区别?
BeanFactory:IoC 容器接口,管理所有 BeanFactoryBean:一种特殊 Bean,getObject()返回的是它生产的目标对象,而非 FactoryBean 本身。&beanName可获取 FactoryBean 实例,beanName获取目标对象。MyBatis 的MapperFactoryBean是典型实现。
Q5:单例 Bean 是线程安全的吗?
不是。Spring 单例只保证容器中只有一个实例,不保证线程安全。若 Bean 中有可变状态(成员变量),需自行加锁或使用 ThreadLocal。无状态 Bean(Controller / Service 通常无状态字段)天然安全。
Q6:prototype Bean 会执行销毁方法吗?
不会。Spring 不会跟踪 prototype Bean 的生命周期,容器不持有其引用,@PreDestroy 和 destroy-method 不会被调用。需手动管理。
参考资料
评论 (0)
发表评论