@PostConstruct 和 @PreDestroy 是 JSR-250(Dependency Injection for Java)标准中定义的生命周期注解,用于标记 Bean 的初始化后和销毁前方法。Spring 框架完整支持这两个注解,通过它们可以在 Bean 的生命周期关键节点执行自定义逻辑(如资源初始化、清理)。以下从注解定义、源码解析、生命周期执行时机、使用场景及注意事项展开详细说明。
一、注解定义与源码解析
1. @PostConstruct 注解
@PostConstruct 位于 javax.annotation 包(Jakarta EE 9+ 后移至 jakarta.annotation),其源码定义如下(简化版):
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PostConstruct {
}
关键特性:
- 标记一个方法在 Bean 的依赖注入完成后、初始化完成前执行(即“后构造”阶段)。
- 方法可以是
public、protected或private,但不能是static或带参数。
2. @PreDestroy 注解
@PreDestroy 同样位于 javax.annotation 包,源码定义如下:
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PreDestroy {
}
关键特性:
- 标记一个方法在 Bean 的销毁前执行(即“预销毁”阶段)。
- 方法签名要求与
@PostConstruct一致(非静态、无参数)。
二、生命周期执行时机:Spring 中的调用顺序
在 Spring Bean 的生命周期中,@PostConstruct 和 @PreDestroy 的执行时机严格遵循以下顺序:
1. @PostConstruct 的执行时机
Bean 的生命周期阶段(简化):
实例化 → 依赖注入 → @PostConstruct 方法 → InitializingBean.afterPropertiesSet() → 自定义初始化方法 → Bean 就绪
具体流程:
- Spring 通过反射创建 Bean 实例(构造器调用)。
- 注入依赖(如
@Autowired字段、方法参数)。 - 调用
@PostConstruct标记的方法(此时 Bean 已完成依赖注入,但未执行其他初始化逻辑)。
2. @PreDestroy 的执行时机
Bean 销毁阶段的顺序:
DisposableBean.destroy() → @PreDestroy 方法 → Bean 销毁(从容器中移除)
具体流程:
- 容器触发 Bean 销毁(如应用关闭、手动调用
destroy())。 - 调用
@PreDestroy标记的方法(此时 Bean 仍可使用,但即将被销毁)。 - 若 Bean 实现了
DisposableBean接口,调用其destroy()方法。
三、典型使用场景与示例
1. @PostConstruct:初始化资源
适用于需要在 Bean 就绪后立即执行的初始化操作(如加载配置、建立连接、初始化缓存)。
示例:初始化数据库连接池
@Service
public class DataSourceService {
private DataSource dataSource;
// 依赖注入(假设通过 @Bean 或 @Autowired 注入)
@Autowired
private DataSourceConfig config;
// @PostConstruct 标记初始化方法
@PostConstruct
public void initDataSource() {
// 使用注入的配置初始化连接池(如 HikariCP)
HikariConfig hikariConfig = new HikariConfig();
hikariConfig.setJdbcUrl(config.getUrl());
hikariConfig.setUsername(config.getUsername());
hikariConfig.setPassword(config.getPassword());
this.dataSource = new HikariDataSource(hikariConfig);
}
public Connection getConnection() throws SQLException {
return dataSource.getConnection(); // 初始化后使用
}
}
2. @PreDestroy:清理资源
适用于需要在 Bean 销毁前释放的资源(如关闭数据库连接、停止定时任务、释放文件句柄)。
示例:关闭数据库连接池
@Service
public class DataSourceService {
private DataSource dataSource;
// 初始化逻辑(同上)
// @PreDestroy 标记清理方法
@PreDestroy
public void closeDataSource() {
if (dataSource != null && dataSource instanceof HikariDataSource) {
((HikariDataSource) dataSource).close(); // 关闭连接池
System.out.println("数据源已关闭");
}
}
}
3. 组合使用:完整的生命周期管理
结合 @PostConstruct 和 @PreDestroy 实现资源的“初始化-使用-清理”闭环。
示例:缓存服务的生命周期管理
@Service
public class CacheService {
private CacheManager cacheManager;
@PostConstruct
public void initCache() {
// 初始化缓存管理器(如 Caffeine)
this.cacheManager = Caffeine.newBuilder()
.maximumSize(1000)
.expireAfterWrite(10, TimeUnit.MINUTES)
.build();
System.out.println("缓存管理器初始化完成");
}
public void put(String key, Object value) {
cacheManager.get(key, k -> value); // 使用缓存
}
@PreDestroy
public void destroyCache() {
if (cacheManager != null) {
cacheManager.invalidateAll(); // 清空缓存
System.out.println("缓存已清空");
}
}
}
四、源码实现细节与关键类
1. CommonAnnotationBeanPostProcessor
Spring 处理 JSR-250 注解(如 @PostConstruct、@PreDestroy、@Resource)的核心类,继承自 InstantiationAwareBeanPostProcessorAdapter。其关键逻辑如下:
(1)postProcessBeforeInitialization 方法
在 Bean 初始化前(InitializingBean.afterPropertiesSet() 之前),扫描并调用 @PostConstruct 标记的方法。
(2)postProcessBeforeDestruction 方法
在 Bean 销毁前,扫描并调用 @PreDestroy 标记的方法。
2. 执行顺序的底层控制
Spring 通过以下顺序确保生命周期方法的正确调用:
- 构造器调用 → 2. 依赖注入 → 3.
@PostConstruct方法 → 4.InitializingBean.afterPropertiesSet()→ 5. 自定义初始化方法 → 6. Bean 就绪 → … → 销毁阶段:DisposableBean.destroy()→@PreDestroy方法 → Bean 移除。
五、注意事项与常见问题
1. 方法签名限制
- 方法必须是非静态(
static方法无法访问实例变量)。 - 方法不能有参数(Spring 无法传递参数)。
- 方法的返回值类型应为
void(无返回值)。
2. 与 InitializingBean/DisposableBean 的关系
@PostConstruct的执行早于InitializingBean.afterPropertiesSet()。@PreDestroy的执行早于DisposableBean.destroy()。- 推荐优先使用
@PostConstruct/@PreDestroy(标准注解,与框架解耦),而非直接实现接口。
3. 循环依赖的影响
若 Bean 存在循环依赖(如 A 依赖 B,B 依赖 A),@PostConstruct 仍会在依赖注入完成后执行(Spring 通过三级缓存解决循环依赖)。但需注意,此时依赖的 Bean 可能尚未完成自身的 @PostConstruct 方法。
4. 异常处理
@PostConstruct方法抛出异常会导致 Bean 初始化失败(容器启动时报错)。@PreDestroy方法抛出异常会被 Spring 捕获并记录,但不会阻止 Bean 销毁(除非异常未被处理)。
5. 性能优化
- 避免在
@PostConstruct中执行耗时操作(如文件 IO、远程调用),可能导致容器启动缓慢。 @PreDestroy中的资源清理应尽量轻量(如关闭连接而非重新建立)。
六、总结
@PostConstruct 和 @PreDestroy 是 Spring 中管理 Bean 生命周期的核心注解,分别用于初始化后和销毁前执行自定义逻辑。它们的执行时机严格遵循 Spring 的生命周期流程,适用于资源初始化、清理等场景。理解其源码(如 CommonAnnotationBeanPostProcessor 的处理逻辑)和使用规范(如方法签名限制),有助于开发者编写更健壮、可维护的 Spring 应用。
952

被折叠的 条评论
为什么被折叠?



