bigywater.tech
Spring · 1

ApplicationContext.refresh():容器启动的那十几步各做了什么

容器启动时到底做了什么?@Bean 方法是什么时候变成 Bean 的?BeanFactoryPostProcessor 和 BeanPostProcessor 在哪一步被创建?失败了会怎样?这篇把 refresh() 的每一步重写一遍加上计数和时间线,用 Spring Framework 7.0.9 逐步量出来。

6 → 15
invokeBeanFactoryPostProcessors 一步里 BeanDefinition 的数量(@Bean 方法在这里才变成定义)
76456 µs
refresh 12 个步骤里最慢的一步(invokeBeanFactoryPostProcessors)
10 步
refresh 失败之前已经完成的步骤数(第 11 步 finishBeanFactoryInitialization 抛出异常)

十二个步骤

实测 · 本机执行输出
  prepareRefresh                     BeanDefinition  6→ 6  单例  0→ 0     115 µs
  obtainFreshBeanFactory             BeanDefinition  6→ 6  单例  0→ 0      87 µs
  prepareBeanFactory                 BeanDefinition  6→ 6  单例  0→ 4    4081 µs
  postProcessBeanFactory             BeanDefinition  6→ 6  单例  4→ 4       2 µs
  invokeBeanFactoryPostProcessors    BeanDefinition  6→15  单例  4→ 9   76456 µs
  registerBeanPostProcessors         BeanDefinition 15→15  单例  9→12    4683 µs
  initMessageSource                  BeanDefinition 15→15  单例 12→13   26916 µs
  initApplicationEventMulticaster    BeanDefinition 15→15  单例 13→14     681 µs
  onRefresh                          BeanDefinition 15→15  单例 14→14       2 µs
  registerListeners                  BeanDefinition 15→15  单例 14→14      83 µs
  finishBeanFactoryInitialization    BeanDefinition 15→15  单例 14→20   11373 µs
  finishRefresh                      BeanDefinition 15→15  单例 20→21    8001 µs
  refresh 之前的 BeanDefinition:[org.springframework.context.annotation.internalConfigurationAnnotationProcessor, org.springframework.context.annotation.internalAutowiredAnnotationProcessor, org.springframework.context.annotation.internalCommonAnnotationProcessor, org.springframework.context.event.internalEventListenerProcessor, org.springframework.context.event.internalEventListenerFactory, main.Conf]
  prepareBeanFactory 之后的单例:[environment, systemProperties, systemEnvironment, applicationStartup]
  refresh 之后新增的:[main.Conf, bfpp, bpp, a, b, proto, lazyOne, life, init, listener]

每一步前后的 BeanDefinition 数和单例数、耗时都记下来:定义在第 5 步涨,单例分批增加。

回调发生在哪一步

实测 · 本机执行输出
  --- 事件时间线
  invokeBeanFactoryPostProcessors 构造 Bfpp(BeanFactoryPostProcessor)
  invokeBeanFactoryPostProcessors Bfpp.postProcessBeanFactory:此时 BeanDefinition 共 15 个,单例 9 个
  registerBeanPostProcessors 构造 Bpp(BeanPostProcessor)
  finishBeanFactoryInitialization Bpp 处理 main.Conf
  finishBeanFactoryInitialization 构造 A
  finishBeanFactoryInitialization Bpp 处理 a
  finishBeanFactoryInitialization 构造 B(依赖 A)
  finishBeanFactoryInitialization Bpp 处理 b
  finishBeanFactoryInitialization 构造 Life(SmartLifecycle)
  finishBeanFactoryInitialization Bpp 处理 life
  finishBeanFactoryInitialization 构造 Init
  finishBeanFactoryInitialization Bpp 处理 init
  finishBeanFactoryInitialization Bpp 处理 listener
  finishBeanFactoryInitialization SmartInitializingSingleton.afterSingletonsInstantiated()
  finishRefresh              Life.start()
  finishRefresh              ContextRefreshedEvent
  --- refresh 完成后:getBean(Proto) 两次、getBean(LazyOne) 一次
  refresh 之后                 构造 Proto(prototype)
  refresh 之后                 Bpp 处理 proto
  refresh 之后                 构造 Proto(prototype)
  refresh 之后                 Bpp 处理 proto
  refresh 之后                 构造 LazyOne(@Lazy)
  refresh 之后                 Bpp 处理 lazyOne
  close()                    Life.stop()
  close()                    B.@PreDestroy
  close()                    A.@PreDestroy
  isActive/isRunning:isActive=false isRunning=false
  BeanFactoryPostProcessor 和 BeanPostProcessor 本身也是 Bean,而且要最早被创建(分别在 invokeBeanFactoryPostProcessors、registerBeanPostProcessors 里);普通单例都在 finishBeanFactoryInitialization 里按定义顺序创建,依赖会先于使用者创建;prototype 与 @Lazy 的 Bean 在 refresh 期间不创建;SmartLifecycle.start() 与 ContextRefreshedEvent 在 finishRefresh 里

BeanFactoryPostProcessor 与 BeanPostProcessor 最早创建;普通单例在 finishBeanFactoryInitialization 按依赖顺序创建;prototype 与 @Lazy 不在 refresh 里创建。

失败了会怎样

实测 · 本机执行输出
  失败之前完成了 10 个步骤,最后完成的是 registerListeners(下一步 finishBeanFactoryInitialization 抛出了异常)
  异常 UnsatisfiedDependencyException: Error creating bean with name 'needs' defined in demo.Main$Bad: Unsatisfied dependency expressed through method 'needs' parameter 0: No qualifying bean of type 'demo.Main$Missing' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
  finishBeanFactoryInitialization 构造 A
  finishBeanFactoryInitialization A.@PreDestroy
  失败后 isActive=false

refresh 抛异常时,已经创建的单例会被销毁,上下文不再活跃。

只能刷新一次

实测 · 本机执行输出
  第二次 refresh:IllegalStateException: GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once

GenericApplicationContext 的第二次 refresh 直接抛 IllegalStateException。

分步演示

ApplicationContext.refresh() 的十二步
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK 21.0.12(Homebrew) / Spring Boot 4.0.8(Spring Framework 7.0.9、Tomcat 11.0.24) / Spring Cloud 2025.1.3;用 javac 编译、java 直接运行,依赖由 Maven 从 Maven Central 解析;数字每次运行会有小幅抖动。用的是不带 Boot 的 Spring Framework 7.0.9 的 AnnotationConfigApplicationContext;把 refresh() 里的各个受保护方法重写后在前后插入计数,重写本身有微小的额外开销,µs 数字每次运行会变(例如 invokeBeanFactoryPostProcessors 在几次运行里是 62942 到 76456 µs);Bean 名字里的 main.Conf 是内部类 demo.Main$Conf 的默认名字
    • 没有验证:Spring Boot 的 SpringApplication 上下文(在 onRefresh 里创建内嵌 Web 服务器,见后面的 Boot 篇);ClassPathXmlApplicationContext 是否允许多次 refresh;ConfigurationClassPostProcessor 解析 @Bean 的内部过程;BeanDefinitionRegistryPostProcessor 的先后顺序;大型应用里各步骤的耗时分布
    京ICP备2026067502号-1京公网安备11010502063487号