# 不同IOC的流程解析
作者:Ethan.Yang
博客:https://blog.ethanyang.cn (opens new window)
相关源码参考: Spring源码中文注释仓库5.3.x分支 (opens new window)
在手写 Spring 框架加深理解之后,我们开始系统分析 Spring 源码。 后续源码分析中代码量较大,这里不贴完整源码,请参考 Spring 5.3.x 官方源码或笔者仓库。
切记: 跟着流程多
debug,多观察方法调用顺序!
# 一、Spring 框架体系
# BeanFactory
Spring Bean 的创建是典型的工厂模式,一系列 Bean 工厂共同构成 IoC 容器体系。

接口体系最顶层:
BeanFactory : 最顶层工厂接口,定义了IOC 容器的基本功能规范。
核心子接口:
- ListableBean Factory: 表示容器中的 Bean 可被枚举和查询。
- Hierarchical BeanFactory: 支持父子容器结构,Bean 可继承。
- AutowireCapableBeanFactory: 支持对 Bean 的自动装配(依赖注入)。
这些接口共同定义了 Bean 的集合关系、继承结构以及注入行为,最终由
DefaultListableBeanFactory提供完整实现,作为 Spring 默认的核心 IoC 容器。
提示:
BeanFactory提供基础的 Bean 获取、类型判断、单例/原型判断等能力。具体源码可查阅笔者仓库。
- 补充说明
BeanFactory是最小化功能的容器,强调懒加载(延迟初始化),适合轻量级场景。ApplicationContext是BeanFactory的子接口,提供更丰富的应用框架功能,如国际化、事件发布、AOP 支持等,本章不展开,后续章节将详解。
# BeanDefinition
BeanDefinition 描述 Bean 的配置信息,如类名、作用域、构造参数等。
Spring 中 BeanDefinition 继承体系较为复杂,是容器管理 Bean 配置信息的核心数据结构。

# BeanDefinitionReader
BeanDefinitionReader 负责解析 Spring 配置文件,并将配置信息转为 BeanDefinition。
Spring 提供多种实现,支持 XML、注解、Properties 等格式。

# 二、IOC 容器初始化流程
本章节解析三种常见初始化方式:Web、XML、注解。
# 1 Web IOC 初始化准备工作
在手写源码中,Web IOC 容器的初始化逻辑主要集中在 DispatcherServlet 的 init() 方法中。需要注意的是,init() 方法重写自父类 HttpServletBean,但其核心初始化逻辑在 initServletBean() 方法里完成。
# 入口
Servlet 容器启动,调用 DispatcherServlet.init(),实际调用父类 HttpServletBean.init()(模板方法)
关键点
- Servlet 容器调用
Servlet.init(ServletConfig)。 HttpServletBean继承 Servlet,重写init(ServletConfig)。HttpServletBean.init()做通用初始化,调用抽象模板方法initServletBean()。DispatcherServlet继承自HttpServletBean,重写initServletBean()实现具体初始化。
Servlet 容器调用
│
▼
HttpServletBean.init(ServletConfig) ←—— 父类统一入口
│
│-- 解析 init-param 注入属性
│
│-- 调用 initServletBean() (抽象方法)
▼
DispatcherServlet.initServletBean() ←—— 子类具体初始化
2
3
4
5
6
7
8
9
10
11
# 核心初始化方法
initServletBean()方法是 Spring Web 容器启动的核心控制点,管理整个生命周期。
DispatcherServlet.initServletBean()
│
│-- 记录初始化日志
│
│-- 调用 initWebApplicationContext()
│
│-- 调用 initFrameworkServlet()
│
└─ 记录初始化完成日志
2
3
4
5
6
7
8
9
说明:
initWebApplicationContext()获取或创建 Spring Web 容器。initFrameworkServlet()可执行其他初始化操作(可选)。
# 获取或创建 WebApplicationContext
FrameworkServlet.initWebApplicationContext()
│
│-- 从 ContextLoaderListener 获取根容器
│ (WebApplicationContextUtils.getWebApplicationContext)
│
│-- 判断 DispatcherServlet 是否已有 WebApplicationContext
│ ├─ 有且未激活,则调用 configureAndRefreshWebApplicationContext()
│ │ │
│ │ └─ 调用 ConfigurableWebApplicationContext.refresh()
│ │ (IOC 容器启动)
│ ├─ 有且已激活,直接使用
│ └─ 无,则创建新的 WebApplicationContext 并刷新
│ (createWebApplicationContext() + configureAndRefreshWebApplicationContext())
│ │
│ └─ 调用 ConfigurableWebApplicationContext.refresh()
│ (IOC 容器启动)
│
│-- 发布 WebApplicationContext 到 ServletContext
│ (ServletContext.setAttribute)
│
└─ 调用 onRefresh(WebApplicationContext) 初始化 Spring MVC 组件
(FrameworkServlet.onRefresh() -> DispatcherServlet.onRefresh())
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
说明:
refresh()是 IOC 容器启动的核心入口,完成 Bean 的加载、实例化和依赖注入。onRefresh()初始化 MVC 核心组件,如 HandlerMapping、ViewResolver 等, 即refresh()中留给子类实现的方法。
至此,Web IOC 初始化准备完成。
# 2 XML 的 IOC 初始化准备工作
XML IOC 初始化主要包含三个步骤:BeanDefinition 的资源定位、加载和注册。
以 ApplicationContext 为例,Web 项目中常用 WebApplicationContext 是其子类。

ApplicationContext 支持上下文的嵌套,通过维护父上下文形成一个上下文体系。进行 Bean 查找时,首先在当前上下文中查找,若未找到,则逐级向上查找父上下文。这样设计为多个 Spring 应用提供了共享的 Bean 定义环境。
# 容器启动入口与配置路径解析
用户调用 new ClassPathXmlApplicationContext("application.xml")
│
├─ 触发 ClassPathXmlApplicationContext 构造器
│ ├─ 设置父容器(支持继承和复用 Bean)
│ │
│ ├─ 调用父类 AbstractApplicationContext 构造方法
│ │ ├─ 初始化 ResourcePatternResolver(默认 PathMatchingResourcePatternResolver)
│ │ │ └─ 负责解析 classpath*:、classpath: 等资源路径格式
│ │ │
│ │ └─ 其他基础上下文初始化操作
│ │
│ ├─ 调用 setConfigLocations()
│ │ ├─ 校验并规范配置文件路径
│ │ ├─ 解析占位符(如 ${user.home})
│ │ └─ 将路径转为统一格式,方便资源加载
│ │
│ └─ (如果参数 refresh=true)自动调用 refresh() 启动容器初始化
│
└─ 容器完成基础资源定位和初始化准备
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
说明:
所有 XML/注解上下文类都继承自
AbstractApplicationContext,它通过 装饰器模式 + 策略模式 完成统一初始化逻辑,并最终调用refresh()方法完成容器刷新。在构造阶段,Spring 已将配置文件路径封装为
Resource对象,完成 资源定位。但此时 Bean 尚未解析成 BeanDefinition,真正的解析与注册操作要等到
refresh()调用BeanDefinitionReader时才执行。
# 3 Annotation 的IOC 初始化准备工作
Spring 对注解的定位
- 类级别注解:
@Component、@Repository、@Controller、@Service等 - 类内部注解:
@Autowired、@Value、@Resource等
容器及注解处理
- 主要容器:
AnnotationConfigApplicationContext(普通)和AnnotationConfigWebApplicationContext(Web 版本) - 本节以
AnnotationConfigApplicationContext为例进行源码分析
# 构造器调用及初始化流程
【外部调用】
AnnotationConfigApplicationContext(...)
│
├─► 构造器参数判断
│
├─ 无参构造 → AnnotationConfigApplicationContext()
│ │
│ ├─ 初始化 reader = new AnnotatedBeanDefinitionReader(this)
│ └─ 初始化 scanner = new ClassPathBeanDefinitionScanner(this)
│
├─ (下一步详解)注解类参数 → AnnotationConfigApplicationContext(Class<?>... componentClasses)
│ │
│ ├─ 调用无参构造器 ← 初始化 reader & scanner
│ ├─ register(componentClasses)
│ └─ refresh() // 容器刷新,完成 Bean 初始化
│
└─ (下一步详解)包路径参数 → AnnotationConfigApplicationContext(String... basePackages)
│
├─ 调用无参构造器 ← 初始化 reader & scanner
├─ scan(basePackages)
└─ refresh()
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
两种常用注册方式:
- 直接注册注解 Bean
- 构造器传入具体的 Bean 类
- BeanDefinition 在构造阶段注册,后续
refresh()仅做后续初始化(如 BeanPostProcessor、单例 Bean 实例化等)
- 扫描包路径自动注册
- 构造器传入基础包路径
- 扫描并注册所有候选注解组件
- 如果容器已创建后新增 Bean,需要手动调用
scan()并刷新
# 直接注册注解 Bean 的流程
AnnotationConfigApplicationContext(Class<?>... componentClasses)
│
├─ 1. 初始化
│ └─ 调用 this(),初始化 reader 和 scanner
│
├─ 2. 注册组件 register(componentClasses)
│ └─ 调用 this.reader.register(componentClasses)
│ │
│ └─ 遍历每个 componentClass
│ └─ registerBean(componentClass)
│ └─ doRegisterBean()
│ │
│ ├─ 创建 AnnotatedGenericBeanDefinition(abd)
│ │ └─ 读取注解元信息
│ │
│ ├─ 判断是否跳过注册(@Conditional 条件判断)
│ │
│ ├─ 设置实例供应商 supplier(可选)
│ │
│ ├─ 解析 Scope 元数据(resolveScopeMetadata)
│ │ ├─ 获取 @Scope 注解属性
│ │ └─ 设置 scopeName 和 proxyMode
│ │
│ ├─ 生成 Bean 名称
│ │ └─ 使用 this.beanNameGenerator.generateBeanName(...)
│ │
│ ├─ 处理通用注解(@Lazy、@Primary、@DependsOn 等)
│ │ └─ AnnotationConfigUtils.processCommonDefinitionAnnotations(abd)
│ │
│ ├─ 处理限定符注解(如 @Qualifier)
│ │
│ ├─ 应用自定义 BeanDefinitionCustomizer(可选)
│ │
│ ├─ 封装为 BeanDefinitionHolder
│ │
│ ├─ 创建作用域代理(ScopedProxyMode)
│ │ └─ AnnotationConfigUtils.applyScopedProxyMode(...)
│ │
│ └─ 注册 BeanDefinition 到容器(BeanDefinitionRegistry)
│ └─ BeanDefinitionReaderUtils.registerBeanDefinition(...)
│ ├─ registry.registerBeanDefinition(beanName, definition)
│ └─ registry.registerAlias(...)
│
└─ 3. 刷新容器 refresh()
└─ 完成 Bean 实例化、依赖注入和生命周期管理
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# 扫描包路径自动注册流程
AnnotationConfigApplicationContext(String... basePackages)
│
├─ 1. 初始化容器
│ └─ 调用无参构造器 this()
│
├─ 2. 执行扫描 scan(basePackages)
│ └─ 调用 scanner.scan(basePackages)
│ │
│ ├─ doScan(basePackages)
│ │ ├─ 遍历每个 basePackage
│ │ ├─ 查找带注解的候选组件(findCandidateComponents)
│ │ ├─ 解析 Scope 元数据(ScopeMetadata)
│ │ ├─ 生成 Bean 名称(使用 BeanNameGenerator)
│ │ ├─ 处理通用注解(@Lazy、@Primary 等)
│ │ ├─ 检查 Bean 名称冲突(checkCandidate)
│ │ └─ 注册 BeanDefinition(调用 BeanDefinitionReaderUtils.registerBeanDefinition)
│ │
│ ├─ 注册注解处理器(AnnotationConfigUtils.registerAnnotationConfigProcessors)
│ │ ├─ @AutowiredAnnotationBeanPostProcessor
│ │ ├─ @CommonAnnotationBeanPostProcessor
│ │ └─ @ConfigurationClassPostProcessor 等
│ │
│ └─ 返回已注册的 BeanDefinition 数量
│
└─ 3. 刷新容器 refresh()
└─ 完成 Bean 的实例化、依赖注入和生命周期管理
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 注解 Bean 与 XML Bean 注册对比
- 注解 Bean:在构造阶段通过
register()或构造器完成注册 - XML Bean:在
refresh()调用obtainFreshBeanFactory()时注册
为什么注解 Bean 不会重复注册?
AnnotationConfigApplicationContext构造时已创建DefaultListableBeanFactory- 调用
refresh()时执行:
refreshBeanFactory(); // GenericApplicationContext 空实现
return getBeanFactory(); // 返回已初始化 BeanFactory
2
refreshBeanFactory()不重建 BeanFactory,也不重新注册 BeanDefinition,只设置序列化 ID
因此,构造阶段完成注册后,refresh() 仅做 Bean 后处理和实例化,避免重复注册。
在 Spring Boot 中,启动类和配置类同样在
register()阶段注册,refresh()主要负责配置解析、自动配置展开和 Bean 实例化。
至此, 不同类型IOC容器的准备工作就绪, 开始进行容器的刷新流程refresh()。