@PreDestroy 是 Jakarta EE/Spring 中容器管理 Bean 销毁前执行清理逻辑的注解,仅对容器托管 Bean 有效,要求方法无参、void 返回、非 static,常用于释放资源;手动 new 对象无效,原型 Bean 默认不触发,需注意拼写、包路径及上下文关闭。

@PreDestroy 是 Java EE 和 Jakarta EE 中的生命周期回调注解,用于在对象被容器销毁前执行清理逻辑。它不适用于普通 new 创建的对象,只对由容器(如 Spring、Java EE 应用服务器)管理的 Bean 生效。
必须是容器管理的 Bean 才能触发 @PreDestroy
只有 Spring 管理的单例、原型(需特殊配置)、或 Java EE 中的托管组件(如 @Singleton EJB、CDI Bean)才能响应 @PreDestroy。手动 new 出来的对象调用该方法无效,JVM 不会自动识别或执行。
- Spring 中:Bean 需通过 @Component、@Service 或配置类声明,且上下文正常关闭(如 ApplicationContext.close())
- Web 应用中:通常随应用停止时触发;Spring Boot 内嵌容器关闭时也会触发
- 注意:@PreDestroy 方法不能是 static,也不能有参数,返回值必须为 void
正确声明和使用 @PreDestroy 方法
在 Bean 类中添加一个无参、void 返回、非 static 的方法,并标注 @PreDestroy:
@Component
public class DataService {
private Connection conn;
@PostConstruct
public void init() {
conn = createConnection(); // 模拟资源获取
}
@PreDestroy
public void cleanup() {
if (conn != null && !conn.isClosed()) {
try {
conn.close();
} catch (SQLException e) {
// 记录日志,避免抛出异常导致销毁失败
System.err.println("Failed to close connection: " + e.getMessage());
}
}
}
}
- 推荐在 @PreDestroy 中释放连接、关闭流、注销监听器、清除缓存引用等
- 避免在此方法中调用可能阻塞或耗时过长的操作(如远程调用),否则影响容器关闭速度
- 不要抛出运行时异常以外的受检异常;若必须处理,应捕获并记录
Spring 中的替代方案与注意事项
Spring 还支持实现 DisposableBean 接口或在 @Bean 注解中指定 destroyMethod 属性,效果等价于 @PreDestroy:
立即学习“Java免费学习笔记(深入)”;
- 使用 @Bean(destroyMethod = "close") 可绑定任意命名的清理方法,无需注解
- 若类已有 close() 或 shutdown() 方法,且不想加 @PreDestroy,这种方式更灵活
- 多个销毁机制共存时(如同时实现 DisposableBean 并标注 @PreDestroy),Spring 会按顺序执行全部
- 原型(prototype)Bean 默认不触发 @PreDestroy;如需支持,得配合 CustomScope 或手动注册 DestructionCallback
常见失效原因排查
如果 @PreDestroy 没有执行,优先检查以下几点:
- Bean 是否真的被 Spring 容器管理(确认是否被扫描到、没有被 new 实例覆盖)
- ApplicationContext 是否正常关闭(main 方法中忘记调用 context.close();Spring Boot 一般自动处理)
- 是否误写成 @PreDestory(拼写错误)或导入了错误包(javax.annotation.PreDestroy vs jakarta.annotation.PreDestroy)
- 类是否被 AOP 代理,而清理方法未被代理调用(确保方法是 public,且未被 final 修饰)


















