You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring中@PostConstruct与@PreDestroy注解方法未触发问题排查

Spring原型Bean中@PostConstruct与@PreDestroy未执行问题排查

问题情况

严格按照教程实现Spring项目,Doctor类标注@Component和@Scope("prototype"),并实现BeanNameAware接口。运行后BeanNameAware的setBeanName方法正常执行,但@PostConstruct和@PreDestroy注解的方法完全未被调用。尝试过Stack Overflow上的方案但无效,需排查原因。

相关代码

主类App.java

package com.example;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class App {
    public static void main( String[] args ){

        ApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class);
        Doctor staff = context.getBean(Doctor.class);
        staff.assist();
        staff.setQualification("MBBS");
        System.out.println(staff);

        ((AnnotationConfigApplicationContext) context).close();
    }
}

Doctor类代码

package com.example;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
@Component 
@Scope(scopeName = "prototype")
public class Doctor implements Staff, BeanNameAware{

    private String qualification; 

    @Override
    public String toString() {
        return "Doctor [qualification=" + qualification + "]";
    }

    public void assist(){
        System.out.println("Doctor is assisting");
    }

    @Override
    public void setBeanName(String arg0) {
        System.out.println("Set Bean name method is called");
    }

    @PostConstruct
    public void postConstruct(){
        System.out.println("Post contruct");
    }

    @PreDestroy
    public void preDestroy(){
        System.out.println("Predestroy");
    }

}

Bean配置类BeanConfig.java

package com.example;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(basePackages = "com")
public class BeanConfig {
     
}

运行输出

D:\Java\Spring\spring-tuts\demo> d: && cd d:\Java\Spring\spring-tuts\demo && cmd /C "D:\Java\jdk\jdk-17.0.4.1\bin\java.exe @C:\Users\USER~1\AppData\Local\Temp\cp_352s2qzst60fhnczvuupchjj8.argfile com.example.App "
Set Bean name method is called
Doctor is assisting
Doctor [qualification=MBBS]

原因分析

  1. 原型Bean的生命周期特性:Spring容器对原型Bean仅负责创建、属性注入和初始化环节,创建完成后将Bean管理权完全移交调用者,容器关闭时不会触发原型Bean的销毁回调(即@PreDestroy不会执行)。但本次@PostConstruct也未执行,并非原型Bean默认特性,核心问题在注解依赖上。

  2. JDK版本与注解依赖冲突:你使用的是JDK17,代码中却引用javax.annotation包下的注解。JDK9之后Java模块化移除了javax.annotation包,Spring在高版本JDK下无法识别这些注解,导致注解逻辑失效。

解决方案

1. 替换注解依赖(解决@PostConstruct不执行问题)

在项目依赖中引入Jakarta版本的注解包,并替换代码中的注解导入:

  • Maven依赖:
<dependency>
    <groupId>jakarta.annotation</groupId>
    <artifactId>jakarta.annotation-api</artifactId>
    <version>2.1.1</version>
</dependency>
  • Gradle依赖:
implementation 'jakarta.annotation:jakarta.annotation-api:2.1.1'
  • 替换代码中的导入语句:
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;

2. 手动管理原型Bean的销毁(解决@PreDestroy不执行问题)

由于Spring容器不管理原型Bean的销毁,需手动调用销毁方法:
修改主类代码,在Bean使用完毕后主动调用preDestroy():

public static void main( String[] args ){
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class);
    Doctor staff = context.getBean(Doctor.class);
    staff.assist();
    staff.setQualification("MBBS");
    System.out.println(staff);

    // 手动触发销毁逻辑
    staff.preDestroy();
    context.close();
}

内容的提问来源于stack exchange,提问作者gavi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 03:53:09