专栏文章
专栏文章
Spring Framework 系列
1. Spring Framework 系列 #01:Spring 容器启动流程源码分析 2. Spring Framework 系列 #02:Spring 三级缓存与循环依赖 3. Spring Framework 系列 #03:Spring 事务管理 4. Spring Framework 系列 #04:Spring IoC 与 Bean 生命周期 5. Spring Framework 系列 #05:Spring AOP

Spring Framework 系列 #04:Spring IoC 与 Bean 生命周期

发布于 2026-05-26 09:43 👁 7 次阅读
#源码解析#java#spring

本文从理论溯源出发,经 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 AnnotationConfigApplicationContextSpringApplication

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 阶段)

bean lifecycle

源码主干路径

// 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="...") 指定

销毁顺序与之镜像:@PreDestroydestroy()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() 中触发,@PostConstructCommonAnnotationBeanPostProcessorpostProcessBeforeInitialization 阶段处理,而 afterPropertiesSet 在随后的 invokeInitMethods 中调用。

Q3:@Configuration 加不加有什么区别?

加了是 Full 模式(CGLIB 代理),@Bean 方法互调返回同一实例;不加(或 proxyBeanMethods=false)是 Lite 模式,每次调用 @Bean 方法都 new 新对象。

Q4:BeanFactory 和 FactoryBean 的区别?

Q5:单例 Bean 是线程安全的吗?

不是。Spring 单例只保证容器中只有一个实例,不保证线程安全。若 Bean 中有可变状态(成员变量),需自行加锁或使用 ThreadLocal。无状态 Bean(Controller / Service 通常无状态字段)天然安全。

Q6:prototype Bean 会执行销毁方法吗?

不会。Spring 不会跟踪 prototype Bean 的生命周期,容器不持有其引用,@PreDestroydestroy-method 不会被调用。需手动管理。


参考资料

← 返回列表

评论 (0)

暂无评论,来留下第一条吧。

发表评论