Skip to content

Spring 中的 @PostConstruct 和 @PreDestroy 注解的作用是什么? ​

  • 标签:后端、Spring

🏛 业务架构师 ​

@PostConstruct 和 @PreDestroy 是 Bean 生命周期的两个注解式钩子:

  • @PostConstruct:在依赖注入完成之后、Bean 对外提供服务之前执行一次。用途:初始化内存字典、预热本地缓存、校验必填配置、注册回调——前提是"要用到注入进来的依赖",所以它比构造器合适(构造时依赖还没注入);
  • @PreDestroy:容器关闭、Bean 销毁前执行。用途:释放连接池、关闭线程池、注销注册中心、向 MQ 发送终止信号——优雅停机的标配。

业务价值我最强调 @PreDestroy 在发布安全里的角色:K8s 滚动更新时 Pod 被销毁,如果直接杀死进程,在途请求断裂、数据库连接没释放、任务没做完标记。配合 server.shutdown=graceful + preStop 钩子,@PreDestroy 里的清理逻辑保证"处理完存量、不再接增量、干干净净下线"——这直接决定能不能在工作时间放心发布。

两个实战注意点:

  1. @PostConstruct 里不要做重 IO 的长耗时初始化(远程拉全量数据),会拖慢启动影响扩容,应该放到 ApplicationRunner 异步化或用懒加载兜底;
  2. 它和 InitializingBean/DisposableBean 接口、init-method 效果相同,但注解不耦合 Spring 接口、优先级最高,是团队规范的首选。

🏗 系统架构师 ​

作用:Bean 生命周期回调(JSR-250):@PostConstruct 在依赖注入完成后执行,@PreDestroy 在容器关闭时执行。与 InitializingBean/DisposableBean 同类,但解耦于 Spring 接口,是推荐用法。

架构师看这两个注解的真正价值是「资源对称管理」:连接、线程池、文件句柄的创建与释放成对出现在相邻位置,避免初始化散落构造器、清理依赖零散 shutdown hook 的漂移风险。

生产注意点:

  1. 不要在 @PostConstruct 里做重活——它阻塞启动主线程,耗时初始化(预热、大缓存加载)应放 ApplicationReadyEvent 或 Runner,并评估是否该后移到 readiness 打开之后;
  2. 优雅停机靠 @PreDestroy 链路:K8s SIGTERM → 摘流 → 容器 close 触发销毁回调(关线程池、flush 缓冲、提交 offset)→ 退出,预算控制在 terminationGracePeriodSeconds 内。漏掉任何一步,滚动发布就丢数据;
  3. 初始化失败要让它直接失败——启动失败好过带病运行。

💻 全栈开发专家 ​

@PostConstruct:依赖注入完成后、Bean 投入使用前执行一次,做初始化;@PreDestroy:容器销毁前执行,做资源释放。注意 Boot 3.x 起包名从 javax.annotation 变成 jakarta.annotation(迁移时全局替换),由 CommonAnnotationBeanPostProcessor 触发。

java
@Component
public class DictCache {
    private final DictMapper dictMapper;
    private Map<String, String> cache;

    public DictCache(DictMapper dictMapper) { this.dictMapper = dictMapper; }

    @PostConstruct
    public void warmUp() {
        this.cache = dictMapper.loadAll().stream()
                .collect(Collectors.toMap(Dict::code, Dict::label));
        if (cache.isEmpty()) throw new IllegalStateException("字典为空,禁止启动");
    }

    @PreDestroy
    public void shutdown() { log.info("dict cache destroyed"); }
}

要点:@PostConstruct 执行时依赖已注入完(对比构造器时点),且抛异常会中断启动——我用这个特性做配置兜底校验,带病启动不如早点死。时序链:构造器 → @PostConstruct → afterPropertiesSet → initMethod。

坑:@PostConstruct 里干重活会拖慢启动(大缓存预热挪到 ApplicationRunner 异步做,K8s 里启动慢会被探针杀掉)。