Spring Boot Startup Actuator Endpoint – Spring Boot启动执行器端点

最后修改: 2021年 11月 8日

中文/混合/英文(键盘快捷键:t)

1. Introduction

1.绪论

Spring Boot applications can have complex component graphs, startup phases, and resource initialization steps.

Spring Boot应用程序可以有复杂的组件图、启动阶段和资源初始化步骤。

In this article, we’ll take a look at how to track and monitor this startup information via a Spring Boot Actuator endpoint.

在本文中,我们将看看如何通过Spring Boot Actuator端点跟踪和监控该启动信息

2. Application Startup Tracking

2.应用程序启动跟踪

Tracking the various steps during application startup can provide useful information that can help us to understand the time spent during various phases of application startup. Such instrumentation can also improve our understanding of the context lifecycle and the application startup sequence.

跟踪应用程序启动期间的各种步骤可以提供有用的信息,帮助我们了解在应用程序启动的各个阶段所花费的时间。这样的仪表还可以提高我们对上下文生命周期和应用程序启动顺序的理解

The Spring Framework provides the functionality to record the application startup and graph initialization. In addition, Spring Boot Actuator provides several production-grade monitoring and management capabilities via HTTP or JMX.

Spring Framework提供了记录应用程序启动和图形初始化的功能。此外,Spring Boot Actuator还通过HTTP或JMX提供了若干生产级别的监控和管理功能。

As of Spring Boot 2.4, application startup tracking metrics are now available through the /actuator/startup endpoint.

Spring Boot 2.4开始,应用启动跟踪指标现在可以通过/actuator/startup端点提供

3. Setup

3.设置

To enable Spring Boot Actuator, let’s add the spring-boot-starter-actuator dependency to our POM:

为了启用Spring Boot Actuator,让我们把spring-boot-starter-actuator依赖性添加到我们的POM中。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
    <version>2.5.4</version>
</dependency>

We’ll also add the spring-boot-starter-web dependency as this is required to access endpoints over HTTP:

我们还将添加spring-boot-starter-web依赖,因为通过HTTP访问端点需要这个。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>2.5.4</version>
</dependency>

In addition, we’ll also expose the required endpoint over HTTP by setting the configuration property in our application.properties file:

此外,我们还将通过在application.properties文件中设置配置属性,通过HTTP公开所需的端点。

management.endpoints.web.exposure.include=startup

Finally, we’ll use curl and jq to query the actuator HTTP endpoint and parse the JSON response, respectively.

最后,我们将使用curljq来分别查询执行器的HTTP端点和解析JSON响应。

4. Actuator Endpoint

4.执行器端点

In order to capture startup events, we need to configure our application with an implementation of the @ApplicationStartup interface. By default, the ApplicationContext for managing the application lifecycle uses a no-op implementation. This obviously performs no startup instrumentation and tracking, for minimal overhead.

为了捕获启动事件,我们需要用@ApplicationStartup接口的实现来配置我们的应用程序。默认情况下,用于管理应用程序生命周期的ApplicationContext使用一个无操作的实现。这显然不执行启动工具和跟踪,以获得最小的开销。

Therefore, unlike other actuator endpoints, we need some additional setup.

因此,与其他执行器端点不同,我们需要一些额外的设置

4.1. Using BufferingApplicationStartup

4.1.使用BufferingApplicationStartup

We need to set the application’s startup configuration to an instance of BufferingApplicationStartup. This is an in-memory implementation of the ApplicationStartup interface provided by Spring Boot. It captures the events during Spring’s startup process and stores them in an internal buffer.

我们需要将应用程序的启动配置设置为BufferingApplicationStartup的实例。这是Spring Boot提供的ApplicationStartup接口的内存中实现。它捕捉Spring启动过程中的事件,并将其存储在一个内部缓冲区中

Let’s start by creating a simple application with this implementation for our application:

让我们先用这个实现为我们的应用程序创建一个简单的应用程序。

@SpringBootApplication
public class StartupTrackingApplication {

    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(StartupTrackingApplication.class);
        app.setApplicationStartup(new BufferingApplicationStartup(2048));
        app.run(args);
    }
}

Here, we’ve also specified a capacity of 2048 for the internal buffer. Once the buffer reaches this capacity for events, no further data will be recorded. Therefore, it’s important that we use an appropriate value to allow storage of events based on the application complexity and the various steps executed during startup.

这里,我们还为内部缓冲区指定了2048的容量。一旦缓冲区的事件达到这个容量,就不会再有数据被记录。因此,我们必须使用一个适当的值,以便根据应用程序的复杂性和启动时执行的各种步骤来存储事件。

Crucially, the actuator endpoint is only available once this implementation is configured.

至关重要的是,执行器端点只有在配置了这个实现后才可用

4.2. startup Endpoint

4.2.startup 端点

Now, we can start our application and query the startup actuator endpoint.

现在,我们可以启动我们的应用程序并查询startup执行器端点。

Let’s use curl to invoke this POST endpoint and format the JSON output using jq:

让我们使用curl来调用这个POST端点,并使用jq格式化JSON输出。

> curl 'http://localhost:8080/actuator/startup' -X POST | jq
{
  "springBootVersion": "2.5.4",
  "timeline": {
    "startTime": "2021-10-17T21:08:00.931660Z",
    "events": [
      {
        "endTime": "2021-10-17T21:08:00.989076Z",
        "duration": "PT0.038859S",
        "startTime": "2021-10-17T21:08:00.950217Z",
        "startupStep": {
          "name": "spring.boot.application.starting",
          "id": 0,
          "tags": [
            {
              "key": "mainApplicationClass",
              "value": "com.baeldung.startup.StartupTrackingApplication"
            }
          ],
          "parentId": null
        }
      },
      {
        "endTime": "2021-10-17T21:08:01.454239Z",
        "duration": "PT0.344867S",
        "startTime": "2021-10-17T21:08:01.109372Z",
        "startupStep": {
          "name": "spring.boot.application.environment-prepared",
          "id": 1,
          "tags": [],
          "parentId": null
        }
      },
      ... other steps not shown
      {
        "endTime": "2021-10-17T21:08:12.199369Z",
        "duration": "PT0.00055S",
        "startTime": "2021-10-17T21:08:12.198819Z",
        "startupStep": {
          "name": "spring.boot.application.running",
          "id": 358,
          "tags": [],
          "parentId": null
        }
      }
    ]
  }
}

As we can see, the detailed JSON response contains a list of instrumented startup events. It contains various details about each step such as the step name, start time, end time, as well as the step timing details. Detailed information about the response structure is available in the Spring Boot Actuator Web API documentation.

正如我们所看到的,详细的JSON响应包含了一个被检测的启动事件的列表。它包含关于每个步骤的各种细节,如步骤名称、开始时间、结束时间以及步骤计时细节。关于响应结构的详细信息可在Spring Boot Actuator Web API文档中找到。

Additionally, the complete list of steps defined in the core container and further details about each step are available in Spring reference documentation.

此外,核心容器中定义的步骤的完整列表以及关于每个步骤的进一步细节可在Spring参考文档中找到。

An important detail to note here is that subsequent invocations of the endpoint do not provide a detailed JSON response. This is because the startup endpoint invocation clears the internal buffer. Therefore, we’ll need to restart the application to invoke the same endpoint and receive the full response again.

这里需要注意的一个重要细节是,随后的端点调用并不提供详细的JSON响应。这是因为启动端点的调用清除了内部缓冲区。因此,我们需要重新启动应用程序来调用同一个端点并再次接收完整的响应。

We should save the payload for further analysis if required.

如果需要的话,我们应该保存有效载荷以便进一步分析

4.3. Filtering Startup Events

4.3.筛选启动事件

As we’ve seen, the buffering implementation has a fixed capacity for storing events in memory. Therefore, it might not be desirable to store a large number of events in the buffer.

正如我们所看到的,缓冲实现有一个固定的容量来存储内存中的事件。因此,在缓冲区中存储大量的事件可能是不可取的。

We can filter the instrumented events and only store those that may be of interest to us:

我们可以过滤仪器化的事件,只存储那些我们可能感兴趣的事件。

BufferingApplicationStartup startup = new BufferingApplicationStartup(2048);
startup.addFilter(startupStep -> startupStep.getName().matches("spring.beans.instantiate");

Here, we’ve used the addFilter method to only instrument steps with the specified name.

在这里,我们使用了addFilter方法,只对具有指定名称的步骤进行检测。

4.4. Custom Instrumentation

4.4.定制仪器

We can also extend BufferingApplicationStartup to provide custom startup tracking behavior to meet our specific instrumentation needs.

我们还可以扩展BufferingApplicationStartup,以提供自定义的启动跟踪行为,从而满足我们特定的仪表需求。

As this instrumentation is particularly valuable in testing environments rather than production, it’s a simple exercise to use a system property and switch between the no-op and buffering or custom implementations.

由于这个工具在测试环境而不是生产环境中特别有价值,使用一个系统属性并在无操作和缓冲或自定义实现之间切换是一个简单的练习。

5. Analyzing Startup Times

5.分析启动时间

As a practical example, let’s try to identify any bean instantiation during startup that might be taking a relatively long time to initialize. For example, this could be cache loading, database connection pooling, or some other expensive initialization during application startup.

作为一个实际的例子,让我们尝试在启动过程中识别任何可能需要相对较长的初始化时间的bean实例化。例如,这可能是缓存加载、数据库连接池或其他一些在应用程序启动期间的昂贵初始化。

We can invoke the endpoint as previously, but this time, we’ll process the output using jq.

我们可以像以前一样调用端点,但这次我们将使用jq处理输出。

As the response is quite verbose, let’s filter on steps that match the name spring.beans.instantiate and sort them by duration:

由于响应相当冗长,让我们过滤一下与spring.beans.instantiate名称相匹配的步骤,并按持续时间排序。

> curl 'http://localhost:8080/actuator/startup' -X POST \
| jq '[.timeline.events
 | sort_by(.duration) | reverse[]
 | select(.startupStep.name | match("spring.beans.instantiate"))
 | {beanName: .startupStep.tags[0].value, duration: .duration}]'

The above expression processes the response JSON to extract timing information:

上述表达式处理响应的JSON,以提取时间信息。

  • Sort the timeline.events array in descending order.
  • Select all steps matching the name spring.beans.instantiate from the sorted array.
  • Create a new JSON object with beanName and the duration from each matching step.

As a result, the output shows a concise, ordered, and filtered view of the various beans instantiated during application startup:

因此,输出显示了在应用程序启动期间实例化的各种Bean的简明、有序和过滤的视图。

[
  {
    "beanName": "resourceInitializer",
    "duration": "PT6.003171S"
  },
  {
    "beanName": "tomcatServletWebServerFactory",
    "duration": "PT0.143958S"
  },
  {
    "beanName": "requestMappingHandlerAdapter",
    "duration": "PT0.14302S"
  },
  ...
]

Here, we can see that the resourceInitializer bean is taking around six seconds during startup. This may be considered as contributing a significant duration to the overall application startup time. Using this approach, we can effectively identify this issue and focus on further investigation and possible solutions.

在这里,我们可以看到resourceInitializer Bean在启动过程中花费了大约6秒。这可能被认为是对整个应用程序启动时间的一个重要贡献。使用这种方法,我们可以有效地识别这个问题,并专注于进一步调查和可能的解决方案

It’s important to note that ApplicationStartup is intended for use only during application startup. In other words, it does not replace Java profilers and metrics collection frameworks for application instrumentation.

需要注意的是,ApplicationStartup仅适用于应用程序启动期间。换句话说,它并不能取代应用仪表的Java剖析器和度量收集框架

6. Conclusion

6.结论

In this article, we looked at how to obtain and analyze detailed startup metrics in a Spring Boot application.

在这篇文章中,我们研究了如何获得和分析Spring Boot应用程序中的详细启动指标。

First, we saw how to enable and configure the Spring Boot Actuator endpoint. Then, we looked at the useful information obtained from this endpoint.

首先,我们看到如何启用和配置Spring Boot Actuator端点。然后,我们看了从这个端点获得的有用信息。

Finally, we looked at an example to analyze this information in order to gain a better understanding of various steps during application startup.

最后,我们看了一个例子来分析这些信息,以便更好地了解应用程序启动期间的各种步骤。

As always, the code for this article is available over on GitHub.

一如既往,本文的代码可在GitHub上获得over