在 Spring 中使用注解配置 Bean 生命周期回调是最简洁、最主流的方式(替代传统 XML 配置和实现接口的方式),核心围绕 初始化回调 和 销毁回调 两类注解展开。我会用「核心注解 + 完整示例 + 注意事项」的方式,帮你快速掌握注解配置的方法。
一、核心注解介绍
Spring 提供了 3 种主流注解来配置生命周期回调(优先级从高到低):
| 注解 | 作用 | 适用场景 | 核心特点 |
|---|---|---|---|
@PostConstruct |
初始化回调(Bean 就绪前) | 初始化资源(连接、配置加载) | JSR-250 标准注解,解耦 Spring |
@PreDestroy |
销毁回调(Bean 销毁前) | 释放资源(关闭连接、线程池) | JSR-250 标准注解,解耦 Spring |
@Bean(initMethod/destroyMethod) |
初始化 / 销毁回调 | 兼容老代码、第三方类(无法加注解) | 基于 @Bean 注解配置,灵活度高 |
注:
@PostConstruct和@PreDestroy是 JDK 标准注解(JSR-250),无需依赖 Spring 特定接口,是开发首选。
二、完整代码示例
下面通过 2 个场景(自定义类 + 第三方类)演示注解配置方式:
场景 1:自定义 Bean(直接加 @PostConstruct/@PreDestroy)
这是最常用的场景,直接在 Bean 的方法上标注注解即可。
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
// 1. 注册为 Spring Bean(@Component 或 @Service/@Repository 等)
@Component
public class DataSourceBean {
// 无参构造器(Spring 实例化 Bean 时执行)
public DataSourceBean() {
System.out.println("步骤1:Bean 实例化(执行构造器)");
}
// 2. 初始化回调(属性赋值完成后执行)
@PostConstruct
public void initDataSource() {
System.out.println("步骤2:执行 @PostConstruct 初始化(创建数据库连接)");
// 自定义逻辑:初始化数据库连接、加载配置、参数校验等
}
// 业务方法(Bean 就绪后调用)
public void queryData() {
System.out.println("步骤3:Bean 就绪(执行业务方法)");
}
// 3. 销毁回调(容器关闭前执行)
@PreDestroy
public void closeDataSource() {
System.out.println("步骤4:执行 @PreDestroy 销毁(关闭数据库连接)");
// 自定义逻辑:关闭连接、释放线程池、清理缓存等
}
}
场景 2:第三方类 / 无法加注解的 Bean(用 @Bean 配置 init/destroy 方法)
如果 Bean 是第三方库的类(无法修改源码加注解),可以通过 @Bean 的 initMethod 和 destroyMethod 属性指定回调方法。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
// 模拟第三方类(无法修改源码,不能加 @PostConstruct/@PreDestroy)
class ThirdPartyConnection {
// 自定义初始化方法(无参数、无返回值)
public void initConnection() {
System.out.println("第三方类:执行初始化(创建连接)");
}
// 自定义销毁方法(无参数、无返回值)
public void closeConnection() {
System.out.println("第三方类:执行销毁(关闭连接)");
}
public void doWork() {
System.out.println("第三方类:执行业务逻辑");
}
}
// 配置类
@Configuration
public class BeanConfig {
// 注册第三方类为 Bean,并指定初始化/销毁方法
@Bean(
initMethod = "initConnection", // 指定初始化回调方法名
destroyMethod = "closeConnection" // 指定销毁回调方法名
)
public ThirdPartyConnection thirdPartyConnection() {
return new ThirdPartyConnection();
}
}
场景 3:测试类(验证回调执行)
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan(basePackages = "com.example") // 扫描@Component 注解的 Bean
public class LifecycleTest {
public static void main(String[] args) {
// 1. 启动 Spring 容器(触发 Bean 实例化、初始化)
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(LifecycleTest.class);
// 2. 获取 Bean 并执行业务方法
DataSourceBean dataSourceBean = context.getBean(DataSourceBean.class);
dataSourceBean.queryData();
ThirdPartyConnection thirdPartyConnection = context.getBean(ThirdPartyConnection.class);
thirdPartyConnection.doWork();
// 3. 关闭容器(触发 Bean 销毁回调)
context.close();
}
}
执行结果(验证顺序)
步骤1:Bean 实例化(执行构造器)
步骤2:执行 @PostConstruct 初始化(创建数据库连接)
第三方类:执行初始化(创建连接)
步骤3:Bean 就绪(执行业务方法)
第三方类:执行业务逻辑
步骤4:执行 @PreDestroy 销毁(关闭数据库连接)
第三方类:执行销毁(关闭连接)
三、关键注意事项
-
注解方法的要求:
@PostConstruct/@PreDestroy标注的方法:无参数、无返回值、访问修饰符任意(public/private 均可),不能抛出检查型异常(RuntimeException 可抛)。@Bean的initMethod/destroyMethod指定的方法:要求同上,方法名必须和类中定义的一致。
-
销毁回调的生效条件:
- 只有 单例 Bean 会执行销毁回调(Spring 容器关闭时触发);
- 原型 Bean(
@Scope("prototype"))由用户手动管理,容器不会调用销毁方法。
-
依赖问题:
@PostConstruct方法执行时,当前 Bean 的所有属性已经完成赋值,可安全使用依赖的其他 Bean;- 不要在构造器中调用依赖的 Bean(此时依赖未注入,会报空指针),优先用
@PostConstruct。
-
JDK 版本兼容:
-
JDK 9+ 移除了 JSR-250 注解(
<dependency> <groupId>jakarta.annotation</groupId> <artifactId>jakarta.annotation-api</artifactId> <version>2.1.1</version> </dependency>@PostConstruct/@PreDestroy),需要手动引入依赖:
-
总结
- 首选方式 :自定义 Bean 直接用
@PostConstruct(初始化)和@PreDestroy(销毁),解耦且简洁; - 兼容场景 :第三方类 / 无法加注解的 Bean,用
@Bean(initMethod/destroyMethod)指定回调方法; - 核心规则:销毁回调仅对单例 Bean 生效,注解方法需满足「无参、无返回值」要求。