如何在Spring Boot 3启动后立即发布@Timed指标
解决Spring Boot 3中@Timed指标未调用不显示的问题
默认情况下,Micrometer的@Timed注解生成的指标是懒加载的,只有方法被调用一次后才会出现在/actuator/prometheus的响应中。要实现启动后直接显示初始值为0的指标,可通过以下两种方式处理:
方法一:手动预注册指定计时器
编写配置类,在应用启动完成后,手动将需要的计时器注册到MeterRegistry中,与@Timed注解的value保持一致:
import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.Timer; import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.context.ApplicationListener; import org.springframework.context.annotation.Configuration; @Configuration public class TimedMeterInitializer implements ApplicationListener<ApplicationReadyEvent> { private final MeterRegistry meterRegistry; public TimedMeterInitializer(MeterRegistry meterRegistry) { this.meterRegistry = meterRegistry; } @Override public void onApplicationEvent(ApplicationReadyEvent event) { // 对应@Timed(value = "get_all_books")的指标 Timer.builder("get_all_books") .percentiles(0.95) // 与注解中的percentiles配置一致 .register(meterRegistry); } }
方法二:自动扫描@Timed注解并注册计时器
如果有多个带@Timed注解的方法,可通过扫描Spring管理的Bean,自动识别并注册所有对应计时器,避免手动逐个添加:
import io.micrometer.core.annotation.Timed; import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.Timer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.context.ApplicationListener; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.AnnotationUtils; import java.lang.reflect.Method; import java.util.Set; @Configuration public class AutoRegisterTimedMeters implements ApplicationListener<ApplicationReadyEvent> { private final MeterRegistry meterRegistry; private final Set<Object> springComponents; @Autowired public AutoRegisterTimedMeters(MeterRegistry meterRegistry, Set<Object> springComponents) { this.meterRegistry = meterRegistry; this.springComponents = springComponents; } @Override public void onApplicationEvent(ApplicationReadyEvent event) { for (Object component : springComponents) { Class<?> clazz = component.getClass(); for (Method method : clazz.getDeclaredMethods()) { Timed timedAnnotation = AnnotationUtils.findAnnotation(method, Timed.class); if (timedAnnotation != null) { // 优先使用注解指定的value,否则用方法名作为指标名 String metricName = timedAnnotation.value().isEmpty() ? method.getName() : timedAnnotation.value(); Timer.Builder timerBuilder = Timer.builder(metricName); // 同步注解中的percentiles配置 if (timedAnnotation.percentiles().length > 0) { timerBuilder.percentiles(timedAnnotation.percentiles()); } // 同步注解中的描述信息(如果有) if (!timedAnnotation.description().isEmpty()) { timerBuilder.description(timedAnnotation.description()); } timerBuilder.register(meterRegistry); } } } } }
额外验证配置
确保Actuator的Prometheus端点已开启,在application.properties或application.yml中添加:
# 暴露prometheus端点 management.endpoints.web.exposure.include=prometheus # 启用Prometheus指标导出 management.metrics.export.prometheus.enabled=true
完成以上配置后,启动应用即可在GET /actuator/prometheus响应中看到未调用方法对应的指标(初始值为0)。
内容的提问来源于stack exchange,提问作者SavinI
相关产品推荐
相关产品推荐

