@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 这两个名字。