目录
正在加载目录…
专栏文章
专栏文章
Spring Framework 系列
1. Spring 容器启动:refresh 流程与源码解析 2. Spring 三级缓存:循环依赖与 AOP 代理 3. Spring 事务:传播机制、执行链路与常见陷阱 4. Spring IoC:Bean 生命周期与扩展机制 5. Spring AOP:动态代理、通知链与 AspectJ 6. Spring 术语速查:核心概念与常用缩写

Spring IoC:Bean 生命周期与扩展机制

发布于 2026-05-26 09:43 · 最后编辑于 2026-07-31 15:53 · 字数 5,170 👁 70 次阅读

本文从理论溯源出发,经 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,层次结构
BeanDefinitionBean 的"配方",加载方式与核心字段
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 LocatorDependency 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

维度BeanFactoryApplicationContext
定位最基础的容器接口,只管 Bean 的获取企业级容器,扩展了 BeanFactory
加载时机懒加载(getBean 时才实例化)启动时预加载所有单例 Bean
额外能力国际化、事件发布、资源加载、ApplicationListener
典型实现DefaultListableBeanFactoryAnnotationConfigApplicationContextSpringApplication

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

../../../assets/04 Spring IoC 与 Bean 生命周期/file 20260605123840468

源码主干路径

// 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
AbstractAutoProxyCreatorAOP 代理创建(postProcessAfterInitialization
ApplicationContextAwareProcessorApplicationContextAware 等 Aware 回调
PersistenceAnnotationBeanPostProcessorJPA @PersistenceContext

BeanFactoryPostProcessor vs BeanPostProcessor

BeanFactoryPostProcessorBeanPostProcessor
作用对象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
处理器AutowiredAnnotationBeanPostProcessorCommonAnnotationBeanPostProcessor
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 模式(@ConfigurationLite 模式(@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 的区别?

  • BeanFactory:IoC 容器接口,管理所有 Bean
  • FactoryBean:一种特殊 Bean,getObject() 返回的是它生产的目标对象,而非 FactoryBean 本身。&beanName 可获取 FactoryBean 实例,beanName 获取目标对象。MyBatis 的 MapperFactoryBean 是典型实现。

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

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

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

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

参考资料

← 返回列表

评论 (0)

暂无评论,来留下第一条吧。
登录注册 后才能发表评论