IoC (Inversion of Control,控制反转) 容器是 Spring Framework 的核心。它负责创建、配置和管理应用程序中的对象(称为 Bean)。IoC 容器的启动过程可以概括为以下几个主要阶段:
1. 容器实例化:
-
创建容器实例: 开发的时候我们通常会选择一个具体的
ApplicationContext
实现类来创建容器。常见的实现类有:ClassPathXmlApplicationContext
: 从类路径加载 XML 配置文件。FileSystemXmlApplicationContext
: 从文件系统加载 XML 配置文件。AnnotationConfigApplicationContext
: 基于 Java 注解配置。WebApplicationContext
: 用于 Web 应用(通常由 Spring Boot 自动配置)。
// 使用 XML 配置 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); // 使用 Java 注解配置 ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
2. 加载 Bean 定义 (Bean Definition):
-
读取配置元数据: 容器会读取配置元数据,这些元数据描述了如何创建和配置 Bean。元数据可以来自:
- XML 配置文件:
<bean>
标签定义了 Bean 的类名、属性、依赖关系等。 - Java 注解:
@Component
、@Service
、@Repository
、@Controller
、@Configuration
、@Bean
等注解定义了 Bean。 - Java 配置类: 使用
@Configuration
注解的类,其中使用@Bean
注解的方法定义了 Bean。
- XML 配置文件:
-
解析配置元数据: 容器会解析这些元数据,并将其转换为内部的
BeanDefinition
对象。BeanDefinition
包含了 Bean 的所有信息,例如:- Bean 的类名 (Class Name)。
- Bean 的作用域 (Scope,如 singleton、prototype)。
- Bean 的构造函数参数。
- Bean 的属性值。
- Bean 的依赖关系 (Dependencies)。
- Bean 的初始化方法 (Init Method) 和销毁方法 (Destroy Method)。
- Bean 是否是懒加载 (Lazy Initialization)。
-
注册 Bean 定义: 解析后的
BeanDefinition
对象会被注册到容器内部的一个BeanDefinitionRegistry
中(通常是一个 Map)。
3. Bean 的实例化和依赖注入 (Dependency Injection):
-
Bean 的实例化: 容器根据
BeanDefinition
中的信息,通过反射创建 Bean 的实例。- 构造函数注入: 通过构造函数注入依赖。
- Setter 方法注入: 通过 Setter 方法注入依赖。
- 字段注入: 直接注入到字段 (不推荐)。
-
依赖注入: 容器会解析 Bean 之间的依赖关系,并将依赖的 Bean 注入到需要它们的 Bean 中。
- 自动装配 (Autowiring): 容器可以根据类型、名称或限定符 (Qualifier) 自动查找并注入依赖。
- 手动装配: 开发者可以在 XML 配置或 Java 配置中显式指定依赖关系。
- 循环依赖的处理:容器检测循环依赖, 对于prototype作用域的bean, 会抛出异常. 对于单例的bean, 可以通过三级缓存解决(后面详细说明).
4. Bean 的后置处理 (Post-Processing):
-
BeanPostProcessor: 容器允许开发者通过实现
BeanPostProcessor
接口来干预 Bean 的实例化过程。BeanPostProcessor
有两个方法:postProcessBeforeInitialization
: 在 Bean 的初始化方法(如@PostConstruct
或InitializingBean.afterPropertiesSet
)执行之前调用。postProcessAfterInitialization
: 在 Bean 的初始化方法执行之后调用。
-
Aware 接口: 如果 Bean 实现了 Spring 提供的一些 Aware 接口(如
BeanFactoryAware
、ApplicationContextAware
、BeanNameAware
),容器会在 Bean 初始化时调用这些接口的方法,将相应的资源注入到 Bean 中。 -
初始化方法: 如果 Bean 定义了初始化方法(通过
@PostConstruct
注解、InitializingBean.afterPropertiesSet
方法或 XML 配置中的init-method
属性指定),容器会在依赖注入完成后调用这些方法。
5. 容器就绪:
- 经过以上步骤,IoC 容器完成了 Bean 的创建、配置、依赖注入和后置处理。
- 容器进入就绪状态,可以响应来自应用程序的 Bean 请求。
- 对于单例 Bean (Singleton Scope),容器会一直持有它们的实例,直到容器关闭。
- 对于原型 Bean (Prototype Scope),容器每次都会创建一个新的实例。
6. 容器关闭 :
- 当应用关闭, 可以调用
ConfigurableApplicationContext
接口的close()
方法关闭容器. - 销毁方法: 如果 Bean 定义了销毁方法(通过
@PreDestroy
注解、DisposableBean.destroy
方法或 XML 配置中的destroy-method
属性指定),容器会在关闭时调用这些方法,释放 Bean 占用的资源。
循环依赖的处理 (三级缓存):
Spring 使用三级缓存来解决单例 Bean 之间的循环依赖:
- 一级缓存 (singletonObjects): 存放完全初始化好的 Bean(成品)。
- 二级缓存 (earlySingletonObjects): 存放早期暴露的 Bean(半成品,已实例化但未完成属性注入)。
- 三级缓存 (singletonFactories): 存放 Bean 工厂对象 (ObjectFactory),用于创建 Bean 的早期引用。
处理流程:
- 当创建 Bean A 时,发现它依赖于 Bean B。
- 创建 Bean B 时,发现它依赖于 Bean A。
- 此时,Bean A 已实例化(但未完成属性注入),将其对应的 ObjectFactory 放入三级缓存。
- Bean B 可以从三级缓存获取 Bean A 的早期引用,完成自身的属性注入。
- Bean B 完成初始化后,放入一级缓存。
- Bean A 继续完成属性注入(此时可以从一级缓存获取到已完成初始化的 Bean B),然后放入一级缓存。
总结流程图:
+---------------------+
| 1. 容器实例化 |
| (ApplicationContext) |
+---------------------+
|
V
+-------------------------------------------------------------------------+
| 2. 加载 Bean 定义 |
| +-----------------+ +-----------------+ +-------------------+ |
| | 读取配置元数据 |---->| 解析配置元数据 |---->| 注册 BeanDefinition | |
| | (XML, Annotations, | | (转换为 | | (到 BeanDefinition | |
| | Java Config) | | BeanDefinition) | | Registry) | |
| +-----------------+ +-----------------+ +-------------------+ |
+-------------------------------------------------------------------------+
|
V
+-----------------------------------------------------------------------------+
| 3. Bean 的实例化和依赖注入 |
| +----------------+ +----------------+ +---------------------+ |
| | Bean 实例化 |----->| 依赖注入 |----->| 循环依赖处理 | |
| | (反射, 构造函数) | | (自动装配, 手动) | | (三级缓存) | |
| +----------------+ +----------------+ +---------------------+ |
+-----------------------------------------------------------------------------+
|
V
+-------------------------------------------------------------------------------+
| 4. Bean 的后置处理 |
| +-----------------------+ +----------------+ +------------------------+ |
| | BeanPostProcessor | | Aware 接口 | | 初始化方法 | |
| | (before/after init) | | (注入资源) | | (@PostConstruct, init-method) | |
| +-----------------------+ +----------------+ +------------------------+ |
+-------------------------------------------------------------------------------+
|
V
+---------------------+
| 5. 容器就绪 |
+---------------------+
|
V (可选)
+---------------------+
| 6. 容器关闭 |
| (销毁方法) |
+---------------------+