1. 概述
本文将带你掌握 Spring Boot 3 的可观测性配置。可观测性是指仅通过系统的外部输出(日志、指标和链路追踪)来衡量其内部状态的能力。基础概念可参考《分布式系统可观测性》一文。
⚠️ 需特别注意:Spring Boot 2 (Spring 5) 和 Spring Boot 3 (Spring 6) 之间存在重大变化。Spring 6 推出了 Spring Observability 新方案,它基于 Micrometer 和 Micrometer Tracing(原 Spring Cloud Sleuth)构建。该方案能更高效地记录应用指标,并通过 OpenZipkin Brave 或 OpenTelemetry 等提供商实现链路追踪。Spring Observability 相比基于代理的可观测性方案优势明显:它能在原生编译的 Spring 应用中无缝运行,并提供更有效的信息。
本文仅聚焦 Spring Boot 3 的实现细节。如需从 Spring Boot 2 迁移,可参考官方迁移指南。
2. Micrometer Observation API
Micrometer 是一个提供厂商中立的应用指标门面的项目。它定义了仪表、速率聚合、计数器、仪表盘和计时器等概念,各厂商可将其适配到自己的工具中。核心组件是Observation API,支持一次编写代码即可实现多种功能。
该 API 已集成到 Spring Framework 的多个组件中,因此理解它是掌握 Spring Boot 可观测性的关键。我们通过一个简单示例来学习。
2.1. Observation 和 ObservationRegistry
根据词典定义,观察是"为科学或其他特殊目的查看或记录事实或事件的行为"。在代码中,我们可以观察单个操作或完整的 HTTP 请求处理过程。在这些观察中,我们可以进行测量、创建分布式追踪的 span 或记录额外信息。
创建观察需要 ObservationRegistry
:
ObservationRegistry observationRegistry = ObservationRegistry.create();
Observation observation = Observation.createNotStarted("sample", observationRegistry);
观察的生命周期如下图所示:
使用 Observation
的方式如下:
observation.start();
try (Observation.Scope scope = observation.openScope()) {
// ... 被观察的操作
} catch (Exception e) {
observation.error(e);
// 异常处理
} finally {
observation.stop();
}
或更简洁的方式:
observation.observe(() -> {
// ... 被观察的操作
});
2.2. ObservationHandler
数据收集代码通过 ObservationHandler
实现。该处理器监听 Observation
的生命周期事件,提供回调方法。一个简单的事件打印处理器实现如下:
public class SimpleLoggingHandler implements ObservationHandler<Observation.Context> {
private static final Logger log = LoggerFactory.getLogger(SimpleLoggingHandler.class);
@Override
public boolean supportsContext(Observation.Context context) {
return true;
}
@Override
public void onStart(Observation.Context context) {
log.info("Starting");
}
@Override
public void onScopeOpened(Observation.Context context) {
log.info("Scope opened");
}
@Override
public void onScopeClosed(Observation.Context context) {
log.info("Scope closed");
}
@Override
public void onStop(Observation.Context context) {
log.info("Stopping");
}
@Override
public void onError(Observation.Context context) {
log.info("Error");
}
}
在创建 Observation
前,需将 ObservationHandler
注册到 ObservationRegistry
:
observationRegistry
.observationConfig()
.observationHandler(new SimpleLoggingHandler());
对于简单日志记录,已有现成实现。例如直接输出到控制台:
observationRegistry
.observationConfig()
.observationHandler(new ObservationTextPublisher(System.out::println));
要使用计时器样本和计数器,可这样配置:
MeterRegistry meterRegistry = new SimpleMeterRegistry();
observationRegistry
.observationConfig()
.observationHandler(new DefaultMeterObservationHandler(meterRegistry));
// ... 使用名为 "sample" 的 Observation
// 获取命名观察的最大持续时间
Optional<Double> maximumDuration = meterRegistry.getMeters().stream()
.filter(m -> "sample".equals(m.getId().getName()))
.flatMap(m -> StreamSupport.stream(m.measure().spliterator(), false))
.filter(ms -> ms.getStatistic() == Statistic.MAX)
.findFirst()
.map(Measurement::getValue);
3. Spring 集成
3.1. Actuator
在 Spring Boot 应用中,通过 Actuator 依赖可获得最佳集成:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
它包含 ObservationAutoConfiguration
,提供可注入的 ObservationRegistry
实例(如果不存在),并配置用于收集指标和链路的 ObservationHandler
。
例如,在服务中创建自定义观察:
@Service
public class GreetingService {
private ObservationRegistry observationRegistry;
// 构造函数
public String sayHello() {
return Observation
.createNotStarted("greetingService", observationRegistry)
.observe(this::sayHelloNoObserver);
}
private String sayHelloNoObserver() {
return "Hello World!";
}
}
此外,它会将 ObservationHandler
Bean 注册到 ObservationRegistry
。我们只需提供 Bean:
@Configuration
public class ObservationTextPublisherConfiguration {
private static final Logger log = LoggerFactory.getLogger(ObservationTextPublisherConfiguration.class);
@Bean
public ObservationHandler<Observation.Context> observationTextPublisher() {
return new ObservationTextPublisher(log::info);
}
}
3.2. Web
MVC 提供了过滤器 org.springframework.web.filter.ServerHttpObservationFilter
用于 HTTP 服务端观察。当应用包含 Actuator 时,该过滤器已自动注册。否则需手动配置:
@Configuration
public class ObservationFilterConfiguration {
// 如果已配置 ObservationRegistry
@ConditionalOnBean(ObservationRegistry.class)
// 如果未使用 Actuator
@ConditionalOnMissingBean(ServerHttpObservationFilter.class)
@Bean
public ServerHttpObservationFilter observationFilter(ObservationRegistry registry) {
return new ServerHttpObservationFilter(registry);
}
}
WebFlux 也有类似过滤器 org.springframework.web.filter.reactive.ServerHttpObservationFilter
,但自 Spring Framework 6.1 (Spring Boot 3.2) 起已弃用。取而代之的是创建 WebHttpHandlerBuilder
。使用 Actuator 时,这也会自动配置。
3.3. AOP
Micrometer Observation API 还提供了基于 AspectJ 的 @Observed
注解和切面实现。要启用此功能,需添加 AOP 依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
然后将切面实现注册为 Spring 管理的 Bean:
@Configuration
public class ObservedAspectConfiguration {
@Bean
public ObservedAspect observedAspect(ObservationRegistry observationRegistry) {
return new ObservedAspect(observationRegistry);
}
}
现在,GreetingService
可简化为:
@Observed(name = "greetingService")
@Service
public class GreetingService {
public String sayHello() {
return "Hello World!";
}
}
结合 Actuator,调用服务后可通过 http://localhost:8080/actuator/metrics/greetingService
获取预配置指标:
{
"name": "greetingService",
"baseUnit": "seconds",
"measurements": [
{
"statistic": "COUNT",
"value": 15
},
{
"statistic": "TOTAL_TIME",
"value": 0.0237577
},
{
"statistic": "MAX",
"value": 0.0035475
}
],
...
}
4. 测试观察
Micrometer Observability API 提供了测试模块。添加以下依赖:
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-observation-test</artifactId>
<scope>test</scope>
</dependency>
micrometer-bom
已包含在 Spring Boot 管理的依赖中,无需指定版本。
默认情况下测试会禁用整个可观测性自动配置,需使用 @AutoConfigureObservability
重新启用。
4.1. TestObservationRegistry
使用 TestObservationRegistry
进行基于 AssertJ 的断言。需将上下文中的 ObservationRegistry
替换为 TestObservationRegistry
实例。
测试 GreetingService
观察的设置示例:
@ExtendWith(SpringExtension.class)
@ComponentScan(basePackageClasses = GreetingService.class)
@EnableAutoConfiguration
@Import(ObservedAspectConfiguration.class)
@AutoConfigureObservability
class GreetingServiceObservationIntegrationTest {
@Autowired
GreetingService service;
@Autowired
TestObservationRegistry registry;
@TestConfiguration
static class ObservationTestConfiguration {
@Bean
TestObservationRegistry observationRegistry() {
return TestObservationRegistry.create();
}
}
// ...
}
也可使用 JUnit 元注解配置:
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import({
ObservedAspectConfiguration.class,
EnableTestObservation.ObservationTestConfiguration.class
})
@AutoConfigureObservability
public @interface EnableTestObservation {
@TestConfiguration
class ObservationTestConfiguration {
@Bean
TestObservationRegistry observationRegistry() {
return TestObservationRegistry.create();
}
}
}
在测试类上添加注解:
@ExtendWith(SpringExtension.class)
@ComponentScan(basePackageClasses = GreetingService.class)
@EnableAutoConfiguration
@EnableTestObservation
class GreetingServiceObservationIntegrationTest {
@Autowired
GreetingService service;
@Autowired
TestObservationRegistry registry;
// ...
}
然后调用服务并验证观察:
import static io.micrometer.observation.tck.TestObservationRegistryAssert.assertThat;
// ...
@Test
void testObservation() {
// 调用服务
service.sayHello();
assertThat(registry)
.hasObservationWithNameEqualTo("greetingService")
.that()
.hasBeenStarted()
.hasBeenStopped();
}
4.2. 观察处理器兼容性套件
测试 ObservationHandler
实现时,可继承以下基类(兼容性套件):
-
NullContextObservationHandlerCompatibilityKit
:测试处理器在参数为null
时的正确性 -
AnyContextObservationHandlerCompatibilityKit
:测试处理器在未指定测试上下文参数时的正确性(包含NullContextObservationHandlerCompatibilityKit
) -
ConcreteContextObservationHandlerCompatibilityKit
:测试处理器在特定上下文类型下的正确性
实现示例:
public class SimpleLoggingHandlerUnitTest
extends AnyContextObservationHandlerCompatibilityKit {
SimpleLoggingHandler handler = new SimpleLoggingHandler();
@Override
public ObservationHandler<Observation.Context> handler() {
return handler;
}
}
测试结果输出:
5. Micrometer Tracing
原 Spring Cloud Sleuth 项目已迁移到 Micrometer,核心变为 Micrometer Tracing(Spring Boot 3 起)。其文档定义如下:
Micrometer Tracing 为流行的追踪库提供简单门面,让你无需绑定厂商即可为 JVM 应用代码添加检测。它旨在为追踪收集活动增加极低开销,同时最大化追踪工作的可移植性。
可独立使用,也通过 ObservationHandler
扩展与 Observation API 集成。
5.1. 集成到 Observation API
添加以下依赖(版本由 Spring Boot 管理):
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing</artifactId>
</dependency>
然后选择支持的追踪器(当前支持 OpenZipkin Brave 或 OpenTelemetry),添加厂商特定集成依赖:
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-bridge-brave</artifactId>
</dependency>
或
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-bridge-otel</artifactId>
</dependency>
Spring Actuator 对两种追踪器都提供自动配置,即注册厂商特定对象和 Micrometer Tracing 的 ObservationHandler
实现,无需额外配置。
5.2. 测试支持
添加测试依赖(版本由 Spring Boot 管理):
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-test</artifactId>
<scope>test</scope>
</dependency>
使用 SimpleTracer
类在测试中收集和验证追踪数据。需将应用上下文中的厂商特定 Tracer
替换为 SimpleTracer
,并使用 @AutoConfigureObservability
启用追踪自动配置。
最小追踪测试配置:
@ExtendWith(SpringExtension.class)
@EnableAutoConfiguration
@AutoConfigureObservability
public class GreetingServiceTracingIntegrationTest {
@TestConfiguration
static class ObservationTestConfiguration {
@Bean
TestObservationRegistry observationRegistry() {
return TestObservationRegistry.create();
}
@Bean
SimpleTracer simpleTracer() {
return new SimpleTracer();
}
}
@Test
void shouldTrace() {
// 测试代码
}
}
或使用 JUnit 元注解:
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@AutoConfigureObservability
@Import({
ObservedAspectConfiguration.class,
EnableTestObservation.ObservationTestConfiguration.class
})
public @interface EnableTestObservation {
@TestConfiguration
class ObservationTestConfiguration {
@Bean
TestObservationRegistry observationRegistry() {
return TestObservationRegistry.create();
}
@Bean
SimpleTracer simpleTracer() {
return new SimpleTracer();
}
}
}
测试 GreetingService
的示例:
import static io.micrometer.tracing.test.simple.TracerAssert.assertThat;
// ...
@Autowired
GreetingService service;
@Autowired
SimpleTracer tracer;
// ...
@Test
void testTracingForGreeting() {
service.sayHello();
assertThat(tracer)
.onlySpan()
.hasNameEqualTo("greeting-service#say-hello")
.isEnded();
}
6. 总结
本文探索了 Micrometer Observation API 及其在 Spring Boot 3 中的集成。我们了解到:
- ✅ Micrometer 是厂商无关的检测 API
- ✅ Micrometer Tracing 是其扩展
- ✅ Actuator 提供预配置的观察和追踪
- ⚠️ 测试默认禁用可观测性自动配置
所有代码实现可在 GitHub 获取。