You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SpringBoot Reactive中Micrometer @Timed注解无法采集方法指标的问题

在SpringBoot响应式流水线中用Micrometer采集方法指标的正确姿势

问题根源

你遇到的问题本质有两个核心原因:

  1. Spring AOP管不到私有方法:TimedAspect是基于Spring AOP实现的,而AOP代理只能拦截公共方法的外部调用。你的transformToComplexStringMethodIssueWithTimed是私有方法,属于类内部直接调用,完全绕过了AOP代理,所以@Timed注解根本不会被触发。
  2. 响应式场景的适配盲区:即使是公共方法,直接用@Timed注解在响应式流水线的同步方法上,虽然能勉强采集,但不符合响应式非阻塞的设计原则,还可能出现上下文丢失的问题。

正确实现方案

下面给出三种可行的方案,按需选择:

方案1:将私有方法改为公共方法+触发AOP代理

把私有方法改成公共方法,同时确保调用时走代理对象(避免内部直接调用绕过AOP):

@Service
public class MyClass {

    // 注入自身的代理对象,用于内部调用触发AOP
    @Autowired
    private MyClass selfProxy;

    public Flux<String> mainReactivePipelineETL() {
        return Flux.interval(Duration.ofSeconds(1))
                .map(i -> selfProxy.transformToComplexStringMethodIssueWithTimed(i));
    }

    @Timed("search_for_me")
    public String transformToComplexStringMethodIssueWithTimed(Long i) {
        // 复杂转换逻辑
        return String.valueOf(i);
    }
}

如果不想注入代理对象,也可以用AopContext.currentProxy(),但需要在启动类添加@EnableAspectJAutoProxy(exposeProxy = true)开启代理暴露。

方案2:编程式调用Micrometer Timer(最灵活,适合私有方法)

不需要依赖AOP,直接在方法内部手动计时,不受方法访问权限限制:

@Service
public class MyClass {

    private final Timer searchTimer;

    // 从MeterRegistry创建并注册Timer
    public MyClass(MeterRegistry registry) {
        this.searchTimer = Timer.builder("search_for_me")
                .description("复杂字符串转换耗时统计")
                .register(registry);
    }

    public Flux<String> mainReactivePipelineETL() {
        return Flux.interval(Duration.ofSeconds(1))
                .map(i -> transformToComplexStringMethodIssueWithTimed(i));
    }

    private String transformToComplexStringMethodIssueWithTimed(Long i) {
        // 用Timer记录方法执行耗时
        return searchTimer.record(() -> {
            // 模拟复杂转换逻辑
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            return String.valueOf(i);
        });
    }
}

方案3:响应式原生Metrics操作符(推荐全响应式链路)

如果你的转换逻辑可以改成响应式返回(Mono),用Micrometer提供的响应式操作符,完全适配非阻塞流水线:

@Service
public class MyClass {

    public Flux<String> mainReactivePipelineETL() {
        return Flux.interval(Duration.ofSeconds(1))
                .flatMap(i -> transformToComplexStringReactive(i)
                        .name("search_for_me")
                        .tag("type", "reactive-transform")
                        .metrics());
    }

    private Mono<String> transformToComplexStringReactive(Long i) {
        return Mono.fromCallable(() -> {
            // 复杂转换逻辑
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            return String.valueOf(i);
        });
    }
}

验证指标

启动应用后,访问/actuator/prometheus端点,搜索search_for_me即可看到对应的指标:

  • search_for_me_total:方法调用总次数
  • search_for_me_seconds:耗时分布(包含分位数、最大值等统计维度)

内容的提问来源于stack exchange,提问作者PatPanda

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 00:13:24