Spring容器生命周期详解
Spring容器生命周期详解
Spring容器的生命周期从启动到关闭分为多个阶段,包括Bean的加载、实例化、初始化、使用和销毁。以下是详细流程和关键点:
1. 容器启动阶段
1.1 容器实例化
- 核心接口:
BeanFactory
(基础容器)或ApplicationContext
(功能丰富的容器)。 - 示例代码:
// BeanFactory方式(基础) BeanFactory factory = new ClassPathXmlApplicationContext("beans.xml"); // ApplicationContext方式(推荐) ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
1.2 BeanDefinition加载
- 作用:读取配置(XML、注解、JavaConfig)并生成Bean定义信息(
BeanDefinition
)。 - 关键流程:
- 解析配置文件(如
beans.xml
或@Configuration
类)。 - 将Bean的元数据(类名、作用域、依赖关系等)存入容器的
BeanFactory
中。
- 解析配置文件(如
2. Bean实例化与初始化阶段
2.1 Bean实例化
- 触发条件:首次获取Bean时或容器启动时(如
prototype
外的所有作用域)。 - 过程:
- 通过反射
newInstance()
或工厂方法创建Bean的实例。 - 不调用初始化方法,仅生成对象。
- 通过反射
2.2 属性注入(依赖注入)
- 过程:
- 根据
BeanDefinition
中的依赖关系,注入其他Bean或属性值。 - 支持字段注入(
@Autowired
)、构造器注入、Setter注入。
- 根据
2.3 初始化方法执行
-
执行顺序:
@PostConstruct
:Java注解,标注的方法在依赖注入后立即执行。- 自定义初始化方法:通过
init-method
属性或@Bean(initMethod="")
指定。 InitializingBean.afterPropertiesSet()
:Spring接口方法。
-
示例代码:
@Service public class MyService { @PostConstruct public void postConstruct() { // 第一个执行 } public void initMethod() { // 通过 <bean init-method="initMethod"/> 或 @Bean(initMethod="initMethod") } @Override public void afterPropertiesSet() { // 最后执行 } }
3. 容器运行阶段
- Bean可用:通过
getBean()
获取并使用Bean实例。 - 作用域管理:
- Singleton:默认,单例,全局唯一。
- Prototype:每次
getBean()
返回新实例。 - 其他:
request
、session
等Web作用域。
4. 容器关闭阶段
4.1 销毁方法执行
-
触发条件:容器关闭时(如
context.close()
)。 -
执行顺序:
@PreDestroy
:Java注解,标注的方法优先执行。- 自定义销毁方法:通过
destroy-method
属性或@Bean(destroyMethod="")
指定。 DisposableBean.destroy()
:Spring接口方法。
-
示例代码:
@Service public class MyService { @PreDestroy public void preDestroy() { // 第一个执行 } public void destroyMethod() { // 通过 <bean destroy-method="destroyMethod"/> 或 @Bean(destroyMethod="destroyMethod") } @Override public void destroy() { // 最后执行 } }
4.2 资源释放
- 容器释放所有Bean实例,关闭底层资源(如数据库连接、线程池)。
关键阶段对比表格
阶段 | 触发时机 | 关键操作 | 注意事项 |
---|---|---|---|
容器实例化 | 程序启动时 | 初始化容器(BeanFactory 或ApplicationContext ) | ApplicationContext 提供更丰富的功能(如事件发布、国际化) |
BeanDefinition加载 | 容器启动时 | 解析配置文件,生成Bean元数据 | 配置错误(如类不存在)会导致容器初始化失败 |
Bean实例化 | 首次获取Bean或容器启动时 | 通过反射或工厂方法创建Bean实例 | 需确保Bean类有无参构造函数(除非使用工厂方法) |
属性注入 | 实例化后 | 注入依赖(其他Bean或值) | 循环依赖需通过ObjectFactory 或@Lazy 解决 |
初始化方法执行 | 属性注入后 | 执行@PostConstruct 、init-method 、InitializingBean | 初始化失败会抛出异常,容器无法启动 |
容器关闭 | 程序结束时 | 执行@PreDestroy 、destroy-method 、DisposableBean | 非singleton 作用域的Bean不会执行销毁方法 |
常见问题与解决方案
-
Bean初始化失败:
- 原因:依赖的Bean未找到或初始化方法抛出异常。
- 解决:检查依赖配置,确保方法无异常。
-
循环依赖:
- 原因:Bean A依赖Bean B,而B又依赖A。
- 解决:
- 使用
@Lazy
延迟注入。 - 通过Setter注入替代构造器注入。
- 使用
-
销毁方法未执行:
- 原因:未显式调用
context.close()
或Bean作用域非singleton
。 - 解决:确保容器正确关闭,或手动调用销毁方法。
- 原因:未显式调用
总结
Spring容器的生命周期分为启动、初始化、运行、关闭四个阶段,每个阶段包含关键步骤(如Bean加载、依赖注入、初始化方法执行)。通过理解这些阶段,可以更好地管理Bean的创建、使用和销毁,避免常见问题(如循环依赖、资源泄漏)。对于复杂场景,建议结合@PostConstruct
/@PreDestroy
和自定义初始化/销毁方法,实现更细粒度的控制。