@PostConstruct 负责某个 Bean 自身的初始化动作,BeanPostProcessor 是容器处理 Bean 实例的扩展点。它们不是互相独立的两个阶段:Spring 对 @PostConstruct 的支持本身就通过后处理器实现。
原来观察到的顺序
2019 年我同时加上相关回调,记录到“自定义 before → PostConstruct → 自定义 after”。这个顺序来自当时的处理器注册与排序,不能推广成所有 postProcessBeforeInitialization 都先于 PostConstruct。
Spring 5 的 CommonAnnotationBeanPostProcessor 识别 javax.annotation.PostConstruct,其父类在 before 回调中调用初始化注解方法。Spring 5 处理器说明、注解初始化调用源码
给观察加上对象名和顺序
下面是 Spring 5、javax.annotation 时代的结构示例;注解 API 需在类路径上。处理器只输出 sample,避免把不同 Bean 的日志混在一起:
import javax.annotation.PostConstruct;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.PriorityOrdered;
public class LifecycleExample {
public static class Sample {
@PostConstruct
public void ready() {
System.out.println("sample: PostConstruct");
}
public void initialize() {
System.out.println("sample: initMethod");
}
}
public static class EarlyProcessor
implements BeanPostProcessor, PriorityOrdered {
@Override
public int getOrder() { return HIGHEST_PRECEDENCE; }
@Override
public Object postProcessBeforeInitialization(Object bean, String name)
throws BeansException {
if ("sample".equals(name)) System.out.println("sample: custom before");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String name)
throws BeansException {
if ("sample".equals(name)) System.out.println("sample: custom after");
return bean;
}
}
@Configuration
public static class Config {
@Bean
public static EarlyProcessor earlyProcessor() {
return new EarlyProcessor();
}
@Bean(initMethod = "initialize")
public Sample sample() {
return new Sample();
}
}
public static void main(String[] args) {
try (AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(Config.class)) {
context.getBean("sample");
}
}
}
在该结构中,自定义处理器以 PriorityOrdered 及最高优先级排在 Spring 5 默认注解处理器之前,所以根据生命周期应先输出 custom before,再到 PostConstruct、initMethod,最后 custom after。这是对指定配置的机制说明,不是任意工程都必须产生相同顺序。Spring 5 默认注解处理器排序
作用范围与版本边界
BeanPostProcessor 按容器作用,不自动处理另一个容器的对象。处理器自身、其依赖及提前创建的基础设施对象,还可能不经过完整的普通 Bean 后处理链,因此“所有对象必经我这个处理器”过于绝对。
较新 Spring 代际使用 jakarta.annotation,不能只改 imports 就假定整个旧依赖组合兼容。排查顺序时先锁定版本、对象名、注册方式与处理器排序,再比较日志,而不是只记住 before 和 after 这两个名字。