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

