Skip to content

应用程序启动步骤 (Application Startup Steps)

本附录列出了核心容器中现有的 StartupSteps 埋点记录。

警告

每个启动步骤的名称和详细信息不属于公共契约(Public Contract),可能会发生变化。这被认为是核心容器的实现细节,并将随其行为变化而调整。

名称描述标签 (Tags)
spring.beans.instantiate实例化 Bean 及其依赖项。beanName: Bean 名称;beanType: 注入点要求的类型。
spring.beans.smart-initialize初始化 SmartInitializingSingleton 类型的 Bean。beanName: Bean 名称。
spring.context.annotated-bean-reader.create创建 AnnotatedBeanDefinitionReader
spring.context.base-packages.scan扫描基础包(Base Packages)。packages: 用于扫描的基础包数组。
spring.context.beans.post-processBean 后处理阶段(Post-processing phase)。
spring.context.bean-factory.post-process调用 BeanFactoryPostProcessor Bean。postProcessor: 当前正在执行的后处理器。
spring.context.beandef-registry.post-process调用 BeanDefinitionRegistryPostProcessor Bean。postProcessor: 当前正在执行的后处理器。
spring.context.component-classes.register通过 AnnotationConfigApplicationContext#register 注册组件类。classes: 待注册的类数组。
spring.context.config-classes.enhance使用 CGLIB 代理增强配置类(Configuration Classes)。classCount: 增强的类数量。
spring.context.config-classes.parse使用 ConfigurationClassPostProcessor 进行配置类解析阶段。classCount: 被处理的类数量。
spring.context.refresh应用程序上下文刷新阶段(Application context refresh phase)。

补充教学

1. 什么是 ApplicationStartup?

在 Spring 5.3 以后,核心容器引入了 ApplicationStartup 接口。它的主要目的是监控和审计应用程序启动期间各个阶段的时间消耗和行为。这对于诊断大型 Spring 应用启动慢的问题非常有帮助。

2. 如何使用这些信息?

Spring 官方提供了几种内置的实现来处理这些启动步骤:

  • BufferingApplicationStartup:将启动步骤缓冲在内存中。你可以通过 HTTP 端点(在 Spring Boot Actuator 中)获取这些指标。
  • FlightRecorderApplicationStartup:专门为 Java Flight Recorder (JFR) 设计。如果你使用 JFR 监控应用,这些 Spring 启动步骤会直接显示在 JFR 事件轴中,与 JVM 级别的事件并行对比。

3. 这些指标背后的性能真相

  • spring.beans.instantiate:这是最常见的性能瓶颈来源。如果你发现某个 beanName 的耗时特别长,通常是因为该 Bean 的构造函数、@PostConstruct 方法或相关的依赖注入逻辑非常耗时(例如建立了远程连接)。
  • spring.context.base-packages.scan:如果你在顶层包(如 com.mycompany)开启了由于范围过大的包扫描,这个步骤的耗时会显著增加,因为它需要读取磁盘上的大量类文件。
  • spring.context.config-classes.enhance:Spring 默认使用 CGLIB 增强标注了 @Configuration 的类,以确保 Bean 方法的单例语义。如果你有大量的配置类,这个过程会产生显著的字节码生成开销。

4. 调试建议

在开发大型复杂应用时,如果启动时间不符合预期,建议开启 JFR 埋点:

java
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.setApplicationStartup(new FlightRecorderApplicationStartup());
context.register(Config.class);
context.refresh();

通过观察 spring.context.refresh 下层的各个细分步骤,你可以精准定位是哪个自定义 Bean 或配置导致了启动缓慢。

Based on Spring Framework.