编辑
2024-05-07
学习记录
00
请注意,本文编写于 765 天前,最后修改于 35 天前,其中某些信息可能已经过时。

目录

核心概念
1. InitializingBean 接口
工作原理
优点
缺点
2. @PostConstruct 注解
工作原理
优点
3. 第三种方式:XML 配置 init-method
总结与推荐
最佳实践:

核心概念

两者都用于定义在 Bean 的所有必要属性(通过依赖注入设置)被设置之后,需要执行的初始化逻辑。例如,在数据库连接池 Bean 被创建且其 dataSource、maxPoolSize 等属性被注入后,你可能需要用它来预先建立几个连接进行预热。

1. InitializingBean 接口

InitializingBean 是 Spring 框架提供的一个接口。

工作原理

Bean 实现这个接口,并强制重写其唯一的 afterPropertiesSet() 方法。Spring 容器在设置完 Bean 的所有属性后,会自动调用这个方法。

java
import org.springframework.beans.factory.InitializingBean; import org.springframework.stereotype.Component; @Component public class MyService implements InitializingBean { private String someProperty; // 这个方法会被 Spring 的依赖注入机制调用 public void setSomeProperty(String someProperty) { this.someProperty = someProperty; } // 实现 InitializingBean 接口的方法 @Override public void afterPropertiesSet() throws Exception { // 在这里编写初始化逻辑 System.out.println("MyService 初始化完成,someProperty 的值为: " + this.someProperty); // 例如:建立数据库连接、加载缓存数据、验证配置等 preloadCache(); } private void preloadCache() { // 模拟预加载缓存 System.out.println("预加载缓存..."); } }

优点

非常明确,直接实现了接口,代码意图清晰。

缺点

与 Spring 框架紧耦合:你的 Bean 类直接引入了 Spring 的特定接口(InitializingBean)。如果你将来想将此类移植到另一个不依赖 Spring 的 IOC 容器中,就需要修改代码。这违反了依赖倒置原则。

2. @PostConstruct 注解

@PostConstruct 是 Java EE 标准注解(javax.annotation.PostConstruct),现在更常见的是来自 Jakarta EE(jakarta.annotation.PostConstruct)。Spring 也完全支持这个注解。

工作原理

你可以在 Bean 的任何一个方法上添加 @PostConstruct 注解。Spring 容器在完成依赖注入后,会识别这个注解并调用该方法。

java
import jakarta.annotation.PostConstruct; import org.springframework.stereotype.Component; @Component public class MyService { private String someProperty; public void setSomeProperty(String someProperty) { this.someProperty = someProperty; } // 使用 @PostConstruct 注解标记初始化方法 @PostConstruct public void init() { // 在这里编写初始化逻辑 System.out.println("使用 @PostConstruct: MyService 初始化完成,someProperty 的值为: " + this.someProperty); preloadCache(); } private void preloadCache() { System.out.println("预加载缓存..."); } }

优点

与框架解耦:这是一个标准注解,不属于 Spring 特有。你的 Bean 类只需要导入 javax.annotation 或 jakarta.annotation 包,而不需要导入任何 Spring 特定的接口。这使得代码更容易移植和测试。

方法名自由:你可以随意命名初始化方法(如 init, startUp, loadConfig 等),比强制使用 afterPropertiesSet 更灵活。

可以定义多个(但不推荐):你可以在一个 Bean 中定义多个 @PostConstruct 方法,但它们的执行顺序是不确定的,通常应避免这样做。

3. 第三种方式:XML 配置 init-method

除了以上两种,Spring 还支持通过 XML 配置来指定初始化方法,这种方式完全没有代码侵入性。

xml <bean id="myService" class="com.example.MyService" init-method="initMethod"> <property name="someProperty" value="someValue"/> </bean> java public class MyService { private String someProperty; public void setSomeProperty(String someProperty) { this.someProperty = someProperty; } // 一个普通的自定义方法 public void initMethod() { System.out.println("使用 XML init-method 进行初始化"); } }

在 Java 配置中,可以使用 @Bean 注解的 initMethod 属性达到同样效果:

java
@Configuration public class AppConfig { @Bean(initMethod = "initMethod") public MyService myService() { return new MyService(); } }

执行顺序 如果一个 Bean 同时使用了这三种方式,它们的执行顺序是:

  • @PostConstruct 注解的方法

  • InitializingBean 接口的 afterPropertiesSet() 方法

  • 自定义的 init-method(在 XML 或 @Bean 中指定)

总结与推荐

特性InitializingBean 接口@PostConstruct 注解XML/Java init-method
耦合性高(紧耦合 Spring)低(标准注解)极低(无代码侵入)
灵活性低(固定方法名)高(任意方法名)高(任意方法名)
代码侵入需要实现接口只需添加注解无需修改类本身
推荐度不推荐( legacy 项目可见)强烈推荐(现代方式)推荐(用于配置外部库的类)

最佳实践:

优先使用 @PostConstruct 注解。它是现代 Spring 应用中最常用、最推荐的方式,因为它结合了低耦合性和高灵活性。

如果你需要配置一个第三方库中的类(你无法修改其源代码)的初始化方法,那么使用 XML 或 Java 配置中的 init-method 是唯一的选择。

尽量避免使用 InitializingBean 接口,除非是为了维护一些遗留的老代码。

本文作者:Weee

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!