docreatebean()中触发扩展点的关键调用是:applybeanpostprocessorsbeforeinitialization()、invokeinitmethods()、applybeanpostprocessorsafterinitialization()、registerdisposablebeanifnecessary();它们分别对应初始化前、初始化、初始化后及销毁注册四个核心扩展时机。

直接说结论:不要试图从头读完 AbstractAutowireCapableBeanFactory 的全部源码,而是盯住 doCreateBean() 方法里那几处关键的回调调用点,它们就是所有扩展点落地的物理位置。
doCreateBean() 里哪几行代码真正触发了扩展点
Spring 6.x 中,doCreateBean() 是 Bean 实例化、初始化、注册全流程的主干方法。它不是“顺序执行”,而是按阶段插入回调——每个扩展点都在这里被显式调用:
-
applyBeanPostProcessorsBeforeInitialization()调用所有BeanPostProcessor.postProcessBeforeInitialization() -
invokeInitMethods()先检查InitializingBean.afterPropertiesSet(),再反射调用@Bean(initMethod)或init-method配置的方法 -
applyBeanPostProcessorsAfterInitialization()调用所有BeanPostProcessor.postProcessAfterInitialization() -
registerDisposableBeanIfNecessary()把DisposableBean.destroy()或destroy-method封装进DisposableBeanAdapter,等容器关闭时触发
这些不是“约定俗成”的钩子,而是硬编码在流程里的真实方法调用。你加一个 @PostConstruct,最终也是被 CommonAnnotationBeanPostProcessor 在 postProcessBeforeInitialization() 里扫描并执行的。
为什么 SmartInitializingSingleton 不在 doCreateBean 里
SmartInitializingSingleton.afterSingletonsInstantiated() 是个例外——它不参与单个 Bean 的生命周期,而是在整个容器刷新流程的后期、所有非懒加载单例都已创建完毕后才被统一回调。它的触发点在 finishBeanFactoryInitialization() 结束之后,属于容器级扩展,不是 Bean 级扩展。
这意味着:
- 它无法访问某个 Bean 的具体属性或状态(因为此时 Bean 可能还没完成初始化)
- 它适合做“全局就绪通知”,比如启动健康检查服务、预热缓存、校验配置一致性
- 它不能替代
@PostConstruct或BeanPostProcessor去干预单个 Bean 的行为
@PostConstruct 和 InitializingBean 的执行顺序怎么确定
两者都发生在“初始化阶段”,但实际执行顺序由 InitDestroyAnnotationBeanPostProcessor 控制,且严格遵循以下优先级:
- 先执行
@PostConstruct标注的方法(通过反射调用,不依赖接口) - 再执行
InitializingBean.afterPropertiesSet() - 最后执行 XML 或
@Bean(initMethod = "...")配置的自定义方法
这个顺序写死在 InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization() 的内部逻辑中,不是靠“谁先注册谁先执行”。如果你同时用了三者,必须按这个顺序设计依赖关系,否则可能拿到未初始化完成的字段值。
最容易被忽略的销毁时机陷阱
销毁逻辑看似简单,但有两处常被误判:
-
@PreDestroy方法不是在 JVM 退出时调用,而是在 Spring 容器调用ConfigurableApplicationContext.close()或AbstractApplicationContext.doClose()时触发——如果应用是 war 包部署在 Tomcat 里,这对应于 ContextLoaderListener 接收到 ServletContextEvent;如果是 Spring Boot,默认会绑定到 JVM shutdown hook,但一旦你禁用了spring.main.register-shutdown-hook=false,@PreDestroy就完全不会执行 -
DisposableBean.destroy()和@PreDestroy是同一轮回调,但destroy-method配置的方法会被包装进DisposableBeanAdapter,和前两者共享同一个执行入口;它们之间没有先后顺序,只是被统一收集、统一遍历调用
换句话说:销毁不是“自动发生”的,它强依赖容器是否被显式关闭。没关容器,哪怕 JVM 还活着,Bean 的销毁逻辑就永远卡在内存里。










