1. 简介
Spring 提供了在 Bean 创建和销毁 时执行自定义逻辑的能力。比如,我们可以通过实现 InitializingBean 和 DisposableBean 接口来完成初始化或销毁操作。
本文将介绍另一种更灵活的方式:使用 @PostConstruct
和 @PreDestroy
注解。
2. @PostConstruct
✅ Spring 在 Bean 属性初始化完成后,仅调用一次被 @PostConstruct
标注的方法。
即使没有需要初始化的内容,该方法也会被执行。需要注意的是:
- 该方法可以是任意访问级别(public、private、protected)
- ❌ 但不能是 static 方法
一个常见的使用场景是:在开发阶段向数据库中插入一些默认数据:
@Component
public class DbInit {
@Autowired
private UserRepository userRepository;
@PostConstruct
private void postConstruct() {
User admin = new User("admin", "admin password");
User normalUser = new User("user", "user password");
userRepository.save(admin, normalUser);
}
}
上面这段代码会在 UserRepository
初始化完成后,自动执行 postConstruct()
方法,完成默认用户的插入。
3. @PreDestroy
✅ Spring 在销毁 Bean 之前,会调用一次被 @PreDestroy
标注的方法。
与 @PostConstruct
类似:
- 方法可以是任意访问级别
- ❌ 同样不能是 static 方法
@Component
public class UserRepository {
private DbConnection dbConnection;
@PreDestroy
public void preDestroy() {
dbConnection.close();
}
}
这个方法通常用于释放资源,比如关闭数据库连接、清理缓存等。
4. javax.annotation 还是 jakarta.annotation?
从 JDK 6 到 JDK 8,@PostConstruct
和 @PreDestroy
都属于标准 Java 库的一部分,位于 javax.annotation
包下。
⚠️ 但从 JDK 9 开始,整个 javax.annotation
包被移出了核心模块,并在 JDK 11 中被彻底移除。
在 Jakarta EE 9 中,该包被迁移到了 jakarta.annotation
。
那么问题来了:我该用 javax.annotation
还是 jakarta.annotation
?
✅ 答案是:看你用的 Spring 版本。
下面这张表总结了 Spring、JDK 和注解命名空间之间的兼容性:
Spring 版本 | JDK 版本 | Java / Jakarta 命名空间 |
---|---|---|
6.1.x | JDK 17 - JDK 23 | jakarta |
6.0.x | JDK 17 - JDK 21 | jakarta |
5.3.x | JDK 8 - JDK 21 | javax |
从表中可以看出:
- Spring 6.0.x 和 6.1.x 使用的是
jakarta
命名空间 - 如果你使用的是 Spring 5.3.x 并且 JDK 9 及以上版本,则必须显式添加
javax.annotation-api
依赖:
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
这段 XML 展示了如何在 Maven 项目的 pom.xml
中添加 javax.annotation-api
依赖。
5. 总结
在这篇文章中,我们介绍了如何使用 @PostConstruct
和 @PreDestroy
注解来控制 Bean 的初始化和销毁逻辑。
这两个注解虽然简单,但在实际开发中非常实用,特别是在需要做一些初始化或资源清理的场景下。
一如既往,所有示例代码都可以在 GitHub 上找到。