Spring IOC生命周期详解!
你好,我是猿java。
这篇文章,我们将通过剖析 Spring 5.x源码,深度分析 IOC 容器的生命周期。
从整体来看,IOC 容器的生命周期包括Bean 的完整生命周期
- 定义阶段:通过配置元数据定义 Bean 的信息。
- 实例化阶段:根据 Bean 定义信息创建 Bean 的实例。
- 属性填充阶段:为 Bean 填充属性,完成依赖注入。
- 初始化阶段:
- 调用
BeanPostProcessor.postProcessBeforeInitialization
方法。 - 执行初始化方法(如通过
@PostConstruct
注解、init-method
属性或实现InitializingBean
接口)。 - 调用
BeanPostProcessor.postProcessAfterInitialization
方法。
- 调用
- 使用阶段:Bean 处于可使用状态,被应用程序使用。
- 销毁阶段:
- 调用
DisposableBean.destroy
方法。 - 执行销毁方法(如通过
@PreDestroy
注解或destroy-method
属性)。
- 调用
4.2 Bean 的作用域与生命周期
Spring 支持多种 Bean 的作用域,每种作用域决定了 Bean 的创建、存储和销毁方式。
4.2.1 Singleton
默认作用域,整个容器只创建一个 Bean 实例,所有对该 Bean 的引用都指向同一个实例。生命周期从容器启动到容器销毁。
4.2.2 Prototype
每次获取 Bean 时都会创建一个新的实例。Spring 对于 Prototype Bean 只负责创建和初始化,不管理其整个生命周期,因此销毁方法不会自动调用。
4.2.3 Request、Session、GlobalSession(Web 作用域)
适用于 Web 应用,分别代表一次 HTTP 请求、一个 HTTP Session 以及全局 HTTP Session 的作用域。
4.3 Bean 的初始化方法与销毁方法
Spring 提供了多种方式来定义 Bean 的初始化和销毁逻辑,帮助开发者在 Bean 生命周期的关键节点执行自定义操作。
4.3.1 初始化方法
实现
InitializingBean
接口:重写afterPropertiesSet
方法。1
2
3
4
5
6public class MyBean implements InitializingBean {
public void afterPropertiesSet() throws Exception {
// 初始化逻辑
}
}@PostConstruct
注解:在方法上使用@PostConstruct
注解,Spring 在 Bean 初始化后自动调用。1
2
3
4
5
6public class MyBean {
public void init() {
// 初始化逻辑
}
}配置
init-method
属性:在 XML 配置或 Java 配置中指定初始化方法。1
<bean id="myBean" class="com.yuanjava.MyBean" init-method="init"/>
1
2
3
4
public MyBean myBean() {
return new MyBean();
}
4.3.2 销毁方法
实现
DisposableBean
接口:重写destroy
方法。1
2
3
4
5
6public class MyBean implements DisposableBean {
public void destroy() throws Exception {
// 销毁逻辑
}
}@PreDestroy
注解:在方法上使用@PreDestroy
注解,Spring 在 Bean 销毁前自动调用。1
2
3
4
5
6public class MyBean {
public void cleanup() {
// 销毁逻辑
}
}配置
destroy-method
属性:在 XML 配置或 Java 配置中指定销毁方法。1
<bean id="myBean" class="com.yuanjava.MyBean" destroy-method="cleanup"/>
1
2
3
4
public MyBean myBean() {
return new MyBean();
}
4.4 Bean 的代理与 AOP 集成
在 Spring 中,通过 AOP(面向切面编程)技术,可以在不改变业务逻辑代码的情况下,为 Bean 添加额外的功能,如事务管理、日志记录等。AOP 的应用会影响 Bean 的生命周期,特别是在创建 Bean 实例时,可能会生成代理对象。
4.5 Bean 的懒加载与预实例化
4.5.1 懒加载 (Lazy Initialization)
默认情况下,Spring 容器会在启动时预先实例化所有的 Singleton Bean。但对于一些启动开销较大的 Bean,可以使用懒加载模式,只有在第一次使用时才进行实例化。通过在 Bean 配置中设置 lazy-init="true"
,或者在注解配置中使用 @Lazy
注解实现。
1 | <bean id="myBean" class="com.yuanjava.MyBean" lazy-init="true"/> |
1 |
|
4.5.2 预实例化
Spring 容器启动时,默认会预实例化所有的 Singleton Bean,以确保 Bean 的可用性。但对于一些不常用或启动开销较大的 Bean,开发者可以选择懒加载模式,优化启动性能。
五、Spring 5.x IOC 容器初始化的详细步骤解析
了解 IOC 容器初始化的详细步骤,有助于开发者更好地理解 Spring 的工作原理,并在实际开发中进行性能优化和问题排查。以下将对 Spring 5.x IOC 容器的初始化步骤进行详细解析。
5.1 ApplicationContext 的创建与刷新
在 Spring 中,ApplicationContext
的创建与刷新是容器初始化的入口。不同的 ApplicationContext
实现类可能会有不同的初始化方式,但基本流程大同小异。
以 AnnotationConfigApplicationContext
为例,其初始化过程如下:
实例化 ApplicationContext:
1
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
AppConfig.class
是基于 Java 注解的配置类。准备 BeanFactory:
- 创建
DefaultListableBeanFactory
实例。 - 设置属性(如类加载器、忽略依赖等)。
- 创建
加载 Bean 定义:
- 如果配置类有
@ComponentScan
,则进行组件扫描。 - 解析配置类,处理
@Bean
方法,生成BeanDefinition
。 - 注册 BeanPostProcessor 等特殊 Bean。
- 如果配置类有
调用
refresh()
方法:refresh()
方法是刷新 ApplicationContext 的核心方法,主要完成以下任务:- 准备阶段:
- 创建、配置
BeanFactory
。 - 添加
BeanPostProcessor
。 - 解析 Bean 的处理器。
- 创建、配置
- 加载 Bean 定义:
- 通过
BeanDefinitionReader
加载 Bean 定义。
- 通过
- 注册 Bean 后处理器:
- 注册内建的
BeanPostProcessor
(如AutowiredAnnotationBeanPostProcessor
)。
- 注册内建的
- 初始化事件发布者:
- 设置 ApplicationContext 的事件发布者,支持事件驱动模型。
- 注册监听器:
- 注册所有实现了
ApplicationListener
接口的监听器。
- 注册所有实现了
- 完成 Bean 创建:
- 根据 Bean 定义创建所有 Singleton Bean。
- 完成刷新:
- 发布容器刷新完成事件。
- 准备阶段:
5.2 Bean 的创建与依赖注入
在 refresh()
方法执行过程中,Spring 会按照一定的顺序创建和装配 Bean,确保所有依赖关系被正确解析和注入。
5.2.1 Bean 的实例化
在实例化 Bean 时,Spring 会根据 BeanDefinition
中的配置信息选择合适的实例化策略。主要步骤包括:
选择实例化策略:
- 对于普通 Bean,使用
SimpleInstantiationStrategy
。 - 对于需要 AOP 代理的 Bean,使用
CglibSubclassingInstantiationStrategy
。
- 对于普通 Bean,使用
调用构造函数创建实例:
- 通过无参构造函数实例化 Bean。
- 或者通过带参数的构造函数注入依赖。
实例化 Bean 的代理对象(如有):
- 如果 Bean 被 AOP 切面代理,生成代理对象替代原始 Bean。
5.2.2 Bean 的属性填充
实例化完成后,Spring 开始进行 Bean 属性的填充,即依赖注入。主要步骤包括:
解析依赖:
- 根据配置元数据解析 Bean 的依赖,如构造函数参数、Setter 方法参数、字段等。
执行自动装配:
- 通过
AutowiredAnnotationBeanPostProcessor
等 BeanPostProcessor 处理@Autowired
注解,实现按类型或按名称装配。
- 通过
处理循环依赖:
- 对于 Singleton Bean,Spring 通过提前暴露一个 ObjectFactory,解决部分循环依赖问题。
- 对于 Prototype Bean,循环依赖无法通过 Spring 自动解决,需要开发者手动处理。
5.2.3 初始化 Bean
完成属性填充后,Spring 进行 Bean 的初始化过程,包括执行 BeanPostProcessor
的前置处理、调用初始化方法、执行 BeanPostProcessor
的后置处理等。
**
BeanPostProcessor.postProcessBeforeInitialization
**:- 调用所有已注册的 BeanPostProcessor 的
postProcessBeforeInitialization
方法,对 Bean 进行前置处理。
- 调用所有已注册的 BeanPostProcessor 的
执行初始化方法:
- 调用
@PostConstruct
注解的方法。 - 调用 Bean 实现的
InitializingBean.afterPropertiesSet
方法。 - 调用配置的
init-method
方法。
- 调用
**
BeanPostProcessor.postProcessAfterInitialization
**:- 调用所有已注册的 BeanPostProcessor 的
postProcessAfterInitialization
方法,对 Bean 进行后置处理。
- 调用所有已注册的 BeanPostProcessor 的
5.3 Bean 的代理与增强
在进行 AOP 相关的 Bean 创建时,Spring 会在 Bean 创建最后阶段,生成代理对象并替换原始 Bean。AOP 的织入主要通过 BeanPostProcessor
来实现,如 AutowiredAnnotationBeanPostProcessor
、CommonAnnotationBeanPostProcessor
等会检查 Bean 是否需要进行代理。
代理的生成主要使用 CGLIB 或 JDK 动态代理,取决于 Bean 是否实现了接口。
1 |
|
通过 @EnableAspectJAutoProxy
注解,Spring 启用基于注解的 AOP 代理,自动为符合切面条件的 Bean 创建代理对象。
5.4 容器的完全刷新与可用
当所有 Bean 都被创建、装配和初始化完毕后,Spring IOC 容器完成了完整的刷新过程,开始接收和处理应用程序的请求。在这个阶段,所有的 Singleton Bean 已经就绪,可以被应用程序中的其他组件使用。
1 | context.refresh(); // 假设使用的是基于模板的 ApplicationContext |
十、总结
Spring 5.x 的 IOC 容器通过其强大的配置与管理能力,为开发者提供了一个高效、灵活且易于扩展的对象管理和依赖注入框架。通过深入了解 IOC 容器的初始化过程、核心组件、生命周期管理以及优化策略,开发者能够更好地应用 Spring 框架,提升应用的性能和可维护性。
本文全面解析了 Spring 5.x IOC 容器的初始化流程,从配置解析、Bean 定义加载与注册、Bean 的实例化与装配、初始化与销毁,到关键类与组件的介绍,再结合实际示例进行了详细说明。此外,还探讨了容器的优化与性能考虑、扩展与定制以及与其他 Spring 模块的集成,为读者提供了一个全面、系统的理解框架。
在实际开发中,合理利用和优化 Spring IOC 容器的各项功能,能够显著提升应用的开发效率和质量。希望通过本文的介绍,读者能够对 Spring 5.x IOC 容器有更加深入的认识,并在实际项目中灵活应用,充分发挥 Spring 框架的强大优势。
6. 学习交流
如果你觉得文章有帮助,请帮忙转发给更多的好友,或关注公众号:猿java,持续输出硬核文章。
