一、IOC容器初始化流程一览

二、详解

2-1、一句话总览

IOC 容器初始化流程,就是 Spring 将项目中的类解析成 BeanDefinition,创建 BeanFactory,再通过刷新容器(refresh)真正创建 Bean 并完成依赖注入的过程。


2-2、全流程结构图

(1)准备阶段:读取配置、扫描类、注册 BeanDefinition
(2)构造容器:创建 BeanFactory、准备 BeanFactory
(3)刷新容器:真正创建 Bean、注入依赖、AOP、初始化等

2-3、详细步骤

阶段一:准备阶段(加载配置信息 → 转成 BeanDefinition)

步骤专业词小白理解
1. 解析配置源XML / 注解 / 配置类读“计划书”
2. 组件扫描@ComponentScan找出“要管理的类”
3. 解析类信息BeanDefinitionReader把类的信息转成可存储结构
4. 注册 BeanDefinitionBeanDefinitionRegistry把“类的说明书”存到容器里

注意:此时 Bean 还没有创建,只是把“要创建什么 Bean”全记录下来了。

你可以理解为:先建立员工档案,还没招人。


阶段二:构造容器(获得 BeanFactory 并做准备)

IOC 容器的核心是 BeanFactory。

步骤小白理解
1. 创建 BeanFactory开一个仓库
2. BeanFactoryPostProcessor 执行调整“档案”/补充配置
3. 注册 BeanPostProcessor准备“加工规则”(AOP 就靠这个)

重点:AOP 和依赖注入的“钩子点”都是在这注册的。

就像厨房先准备锅碗调料,不做菜但把环境准备好。


阶段三:刷新容器 refresh()(真的开始创建 Bean)⭐

这是 IOC 初始化中最重要的核心步骤。

顺序看起来的事情实际发生的机制
1. 实例化 Beannew 出对象构造器执行
2. 依赖注入@Autowired通过 BeanFactory 递归注入
3. 执行 BeanPostProcessor 前置AOP 动态代理发生在这里JDK / CGLIB 代理生成
4. 调用初始化方法@PostConstruct / InitializingBean让 Bean 做初始化工作
5. 执行 BeanPostProcessor 后置Bean 最终定型再次增强或包装

这个阶段才是 IOC 真正“把人招进来并分工上岗”的过程。

【注意】:

此时,实例化的是非懒加载的单例bean,多例bean和懒加载的bean不会在这个阶段实例化,将来用到的时候再创建。


2-4、最后启动 Web 容器(如果是 SpringBoot)

如果是 Web 项目,会再启动:

Tomcat / Jetty / Undertow

然后项目开始对外提供服务。


2-5、小结

IOC 初始化分为三个阶段:

第一阶段,加载配置并扫描组件,将类解析成 BeanDefinition,注册到容器中,但此时不创建对象。

第二阶段,创建 BeanFactory 并执行 BeanFactoryPostProcessor,注册 BeanPostProcessor,完成容器的准备工作。

第三阶段调用 refresh,真正创建 Bean:先实例化,再依赖注入,然后执行 BeanPostProcessor(AOP 代理就是在这产生),最后执行初始化方法,完成整个 Bean 生命周期。

最终,如果是 Web 应用,再启动内置服务器对外提供服务。


三、BeanFactoryPostProcessor 和 BeanPostProcessor

这两个名字很像,但作用、触发时机、能做的事情完全不同。


3-1、一句话总结它们的区别

  • BeanFactoryPostProcessor:在 Bean 创建之前,用来修改 Bean 的配置信息(BeanDefinition)。
  • BeanPostProcessor:在 Bean 创建之后,用来修改 Bean 实例本身(可以做 AOP)。

像这样记:

名字时机作用对象常用用途关键点
BeanFactoryPostProcessorBean 未创建前BeanDefinition(配方)修改 Bean 配置、属性值动 Bean 的“说明书”
BeanPostProcessorBean 已创建后Bean 实例(成品)AOP 增强、注解处理等动 Bean “成品本身”

3-2、深入理解

1) BeanFactoryPostProcessor

触发时机

发生在 容器启动时,Bean 创建之前。

能做什么?

→ 修改 BeanDefinition
比如:

  • 给 Bean 自动加属性

  • 替换 Bean 的依赖

  • 动态修改构造参数

  • 通过它才能做到 @Value、占位符解析(PropertySourcesPlaceholderConfigurer)

典型代码框架
public class MyBFPP implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        BeanDefinition bd = beanFactory.getBeanDefinition("myService");
        bd.getPropertyValues().add("name", "ChangedName");
    }
}

2) BeanPostProcessor

触发时机

Bean 已经 new 出来,并且依赖注入完成以后:

构造器 → 依赖注入 → (这里) before → 初始化 → after
能做什么?

→ 可以操作 Bean 实例本身,尤其是:

  • AOP 动态代理 就是在这里实现(非常重要)

  • @Autowired、@Resource 注入处理也是通过它实现

  • @PostConstruct 生命周期回调也是它触发

常见方法
public class MyBPP implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        System.out.println("初始化之前: " + beanName);
        return bean;
    }
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        System.out.println("初始化之后: " + beanName);
        return bean;
    }
}

3-3、关键结合点 —— AOP 为什么靠 BeanPostProcessor?

因为 AOP 是给 Bean 换成代理对象,必须在 Bean 已经被实例化之后才能替换。
所以 AOP 的核心类 AnnotationAwareAspectJAutoProxyCreator 就是一个 BeanPostProcessor。

你如果理解了这句,你就真正理解了 Spring:

AOP = BeanPostProcessor 在 Bean 初始化后,返回代理对象进行替换。


3-4、小结

BeanFactoryPostProcessor 用来在 Bean 实例创建之前,操作 BeanDefinition。
典型用途是修改 Bean 的配置,比如 PropertySourcesPlaceholderConfigurer 解析配置文件。

BeanPostProcessor 则发生在 Bean 创建之后,用来对 Bean 对象本身进行增强,
AOP 动态代理就是通过 BeanPostProcessor 在 postProcessAfterInitialization 阶段将原始对象替换为代理对象实现的。

更多推荐