在 Spring 容器中,bean 的生命周期涉及多个回调方法的调用。以下是部分方法的调用顺序和它们之间的关系:
调用顺序
-
当一个 bean 实现了setBeanFactory(BeanFactory beanFactory)
BeanFactoryAware
接口时,在属性注入完成后,Spring 会首先调用该方法,用于提供当前的BeanFactory
实例。 -
如果一个 bean 实现了setApplicationContext(ApplicationContext applicationContext)
ApplicationContextAware
接口,Spring 会在调用setBeanFactory
后调用此方法,注入当前的应用上下文实例。 -
这个方法来自于afterPropertiesSet()
InitializingBean
接口,Spring 在所有属性都被设置后(但在@PostConstruct
方法调用之前)调用此方法,用于执行任何初始化逻辑。 -
如果 bean 中存在带有@PostConstruct
@PostConstruct
注解的方法,Spring 将在调用afterPropertiesSet()
方法后调用此方法。这个方法通常用于执行需要依赖于所有属性都已设置的初始化操作。 -
如果 bean 实现了postProcessAfterInitialization(...)
BeanPostProcessor
接口,Spring 会在所有初始化操作(包括@PostConstruct
和afterPropertiesSet()
)完成后调用此方法。通常用于对 bean 进行后处理。 -
如果一个 bean 实现了onApplicationEvent(...)
ApplicationListener
接口,Spring 会在所有的 bean 初始化完成后触发事件。这是“事件处理”逻辑,不在 bean 的初始化顺序中。
总结调用顺序
简要顺序如下(这些都是在当前bean初始化且依赖注入完后调用):
setBeanFactory(...)
setApplicationContext(...)
afterPropertiesSet()
@PostConstruct
postProcessAfterInitialization(...)
onApplicationEvent(...)
(在上下文初始化完成后触发)
示例
您可以通过实现多个接口并观察这些方法的调用顺序来理解它们的生命周期:
public class SpringTest implements BeanFactoryAware, ApplicationContextAware, BeanPostProcessor, InitializingBean, ApplicationListener<ApplicationEvent> {
public SpringTest() throws InterruptedException {
System.out.println("SpringTest constructor 1");
TimeUnit.SECONDS.sleep(2);
}
@Override
public void setBeanFactory(BeanFactory beanFactory) {
System.out.println("setBeanFactory called2");
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
System.out.println("setApplicationContext called3");
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
@PostConstruct
public void init() throws InterruptedException {
System.out.println("@PostConstruct called 4" );
TimeUnit.SECONDS.sleep(2);
}
@Override
public void afterPropertiesSet() throws InterruptedException {
System.out.println("afterPropertiesSet called 5");
TimeUnit.SECONDS.sleep(2);
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessBeforeInitialization called for 6-0(其他bean初始化时也会调用): " + beanName);
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
System.out.println("postProcessAfterInitialization called for 6-1(其他bean初始化时也会调用): " + beanName);
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return bean;
}
@Override
public void onApplicationEvent(ApplicationEvent event) {
System.out.println("onApplicationEvent called for 最后(在上下文初始化完成后触发): " + event);
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
结论
理解这些生命周期回调的顺序对开发 Spring 应用至关重要,特别是在需要在不同阶段执行初始化逻辑时。良好的设计能够确保 bean 的正确初始化和依赖处理。