一、 实现 InitializingBean 接口
通过实现InitializingBean接口并重写afterPropertiesSet()方法,Spring会在依赖注入完成后调用此方法进行初始化。
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
@Component
public class MyBean implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
// 初始化逻辑(在属性注入后执行)
System.out.println("InitializingBean: afterPropertiesSet() called");
}
}
二、 实现 ApplicationContextAware 接口
通过实现ApplicationContextAware接口,Bean可以获取ApplicationContext实例(例如获取其他Bean)。注意:这主要用于获取上下文,初始化逻辑建议结合@PostConstruct使用。
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class ContextAwareBean implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext; // 保存ApplicationContext
System.out.println("ApplicationContext injected");
}
// 可选:结合@PostConstruct执行初始化
@PostConstruct
public void init() {
System.out.println("@PostConstruct in ContextAwareBean");
// 通过applicationContext获取其他Bean等操作
}
}
三、使用 @PostConstruct 注解
✅ 使用条件:
- 只能用在非静态的方法上。
- 方法不能有参数。
- 返回类型必须为
void。 - 通常用于初始化 Bean 的依赖或加载资源。
这是最推荐的方式(JSR-250标准)。在方法上添加
@PostConstruct注解,Spring会在依赖注入后自动调用该方法。
✅ 示例代码:
import javax.annotation.PostConstruct;
import org.springframework.stereotype.Component;
@Component
public class PostConstructBean {
@PostConstruct
public void init() {
// 初始化逻辑(在属性注入后执行)
System.out.println("@PostConstruct: init() called");
}
}
✅调用时机
在 Spring 容器中,一个 Bean 的生命周期大致如下:
-
实例化:Spring 调用构造函数创建 Bean 实例。
-
属性注入:Spring 注入依赖(如其他 Bean 或配置值)。
-
初始化回调:
- 如果 Bean 实现了
InitializingBean接口,则调用 afterPropertiesSet()。 - 如果定义了
@PostConstruct注解方法,则优先调用该方法。
- 如果 Bean 实现了
-
使用 Bean
-
销毁前回调:如
@PreDestroy或DisposableBean.destroy()。
因此,@PostConstruct 是在构造函数和属性注入完成后立即执行的
✅与构造函数的区别
| 对比项 | 构造函数 | @PostConstruct |
|---|---|---|
| 执行时间 | Bean 创建时最先执行 | 构造函数执行后,属性注入完成后执行 |
| 是否支持依赖注入 | ❌ 不支持(此时依赖尚未注入) | ✅ 支持(所有依赖已注入) |
| 是否适合初始化业务逻辑 | ❌ 否 | ✅ 是 |
✅ 原理简析
-
底层机制:
- Spring 框架通过
CommonAnnotationBeanPostProcessor来识别并处理@PostConstruct注解。 - 当 Bean 被创建并完成属性注入后,Spring 会查找带有
@PostConstruct的方法,并反射调用它。
- Spring 框架通过
-
AOP 代理中的行为:
- 如果 Bean 被 AOP 代理包裹,
@PostConstruct方法仍然会在目标对象初始化阶段执行一次,不会受到代理影响。
- 如果 Bean 被 AOP 代理包裹,
✅ 注意事项
- 不要在
@PostConstruct中启动线程或长时间阻塞主线程,这会影响容器启动。 - 避免循环依赖:如果两个 Bean 相互依赖并在
@PostConstruct中调用对方的方法,可能会导致问题。 - 多个
@PostConstruct方法:可以在一个类中定义多个,但它们的执行顺序不确定,建议合并成一个方法。
总结
执行顺序与对比
| 方式 | 执行顺序 | 耦合度 | 推荐度 |
|---|---|---|---|
@PostConstruct | 最先执行 | 无框架耦合 | ★★★★★ |
InitializingBean | 其次执行 | 耦合Spring接口 | ★★★☆☆ |
ApplicationContextAware | 最早注入上下文 | 耦合Spring接口 | ★★★★☆ |
实际初始化逻辑应优先使用@PostConstruct,需要上下文时才结合ApplicationContextAware。
配置要求
确保Spring启用了注解扫描:
<!-- XML配置方式 -->
<context:component-scan base-package="com.example"/>
或使用Java配置:
@Configuration
@ComponentScan("com.example")
public class AppConfig {}
完整示例代码
// 同时使用三种方式的Bean
@Component
public class AllInOneBean implements
ApplicationContextAware, InitializingBean {
private ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext context) {
this.context = context;
System.out.println("ApplicationContext set");
}
@PostConstruct
public void postConstruct() {
System.out.println("@PostConstruct executed");
}
@Override
public void afterPropertiesSet() {
System.out.println("InitializingBean executed");
}
}
输出顺序:
ApplicationContext set
@PostConstruct executed
InitializingBean executed
关键提示:
@PostConstruct是初始化逻辑的首选(解耦、标准)- 需要
ApplicationContext时才实现ApplicationContextAware- 避免在
InitializingBean和@PostConstruct中重复实现相同逻辑