Micrometer 常见注解 详解

Micrometer 常见注解详解

Micrometer 提供了一组强大的注解(Annotations),用于通过 AOP(面向切面编程)的方式,非侵入式地自动采集方法级别的监控指标,如调用次数、执行时间、异常统计等。

这些注解极大地简化了自定义指标的开发,无需在业务代码中手动调用 MeterRegistry,即可实现对关键方法的性能监控。


一、核心注解概览

注解作用
@Counted统计方法调用次数(Counter)
@Timed记录方法执行时间(Timer)
@Metered(已弃用)旧版 Dropwizard 注解,不推荐使用

⚠️ 注意:Micrometer 的注解需配合 AOP 支持(如 Spring AOP 或 AspectJ)才能生效。


二、@Counted 注解详解

1. 作用

  • 自动为方法创建一个 Counter,每次方法成功或失败时递增。
  • 可区分成功与异常调用。

2. 属性说明

属性类型默认值说明
valueString"counter"指标名称(name)
descriptionString""指标描述
countExceptionsbooleanfalse是否对异常也计数
recordFailuresOnlybooleanfalse是否只记录异常调用(失败次数)
extraTagsString[]{}额外标签(key-value 数组)

3. 使用示例

@Service
public class OrderService {

    // 记录方法调用总次数
    @Counted(value = "orders.created", description = "订单创建总次数")
    public void createOrder() {
        // 业务逻辑
    }

    // 只记录异常调用次数
    @Counted(value = "orders.failed", recordFailuresOnly = true)
    public void processPayment() {
        if (Math.random() < 0.1) {
            throw new PaymentException("支付失败");
        }
    }

    // 对所有异常也计数(包括 RuntimeException)
    @Counted(value = "api.calls", countExceptions = true, 
             extraTags = {"method", "checkout"})
    public String checkout() {
        // ...
    }
}

4. 生成的指标示例(Prometheus 格式)

orders_created_total{exception="none"} 42.0
orders_failed_total{exception="PaymentException"} 3.0
api_calls_total{exception="IllegalArgumentException",method="checkout"} 1.0

exception 标签自动记录异常类型,none 表示无异常。


三、@Timed 注解详解

1. 作用

  • 自动为方法创建一个 Timer,记录方法的执行时间。
  • 支持记录分位数(percentiles)、直方图(histogram)等。

2. 属性说明

属性类型默认值说明
valueString"timer"指标名称
descriptionString""描述
percentilesdouble[]{}要发布的分位数(如 0.5, 0.95, 0.99)
publishPercentileHistogrambooleanfalse是否发布百分位直方图(Prometheus 推荐)
extraTagsString[]{}额外标签
longTaskbooleanfalse是否使用 LongTaskTimer(适用于长时间任务)

3. 使用示例

@Service
public class UserService {

    // 记录用户查询耗时
    @Timed(value = "user.service.find", 
           percentiles = {0.5, 0.95, 0.99},
           publishPercentileHistogram = true,
           extraTags = {"category", "read"})
    public User findById(String id) {
        // 模拟延迟
        try { Thread.sleep(100); } catch (InterruptedException e) {}
        return new User(id);
    }

    // 监控长时间运行的任务
    @Timed(value = "batch.job.process", longTask = true)
    public void runBatchJob() {
        // 批处理任务,可能运行几分钟
        Thread.sleep(60_000);
    }
}

4. 生成的指标示例(Prometheus)

# 普通 Timer
user_service_find_seconds_count{category="read"} 100.0
user_service_find_seconds_sum{category="read"} 12.345
user_service_find_seconds_max{category="read"} 0.25
# 分位数(需配置 percentiles)
user_service_find_seconds{quantile="0.5",category="read"} 0.12
user_service_find_seconds{quantile="0.95",category="read"} 0.22

# LongTaskTimer
batch_job_process_seconds_active 1.0
batch_job_process_seconds_duration{...} 60.0

四、注解的底层实现原理

Micrometer 通过 AOP 切面(Aspect)拦截带有注解的方法:

1. CountedAspect

  • 拦截 @Counted 方法
  • 方法执行后调用 counter.increment()
  • 根据是否抛出异常设置 exception 标签

2. TimedAspect

  • 方法开始前记录时间
  • 执行完成后调用 timer.record(duration)
  • 支持 longTask 模式(使用 LongTaskTimer.Sample

3. 自动创建 Meter

  • 第一次调用时,通过 MeterRegistry 创建对应的 CounterTimer
  • 后续调用复用已创建的 Meter

五、启用 Micrometer 注解支持

1. 添加依赖(Maven)

<!-- Spring AOP -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</aspectjweaver>
</dependency>

<!-- Micrometer 注解支持(包含切面) -->
<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-core</artifactId>
</dependency>

micrometer-core 已包含 CountedAspectTimedAspect

2. 启用 AspectJ 自动代理(Spring Boot 默认已启用)

@Configuration
@EnableAspectJAutoProxy  // 通常不需要显式添加
public class MetricsConfig {
}

Spring Boot 会自动配置 AOP 支持。


六、最佳实践与注意事项

✅ 推荐做法

  1. 用于关键业务方法

    @Timed("order.service.create")
    public Order createOrder() { ... }
    
  2. 添加有意义的标签

    @Timed(value = "db.query", extraTags = {"table", "users"})
    
  3. 启用直方图以支持 Prometheus

    @Timed(value = "api.call", publishPercentileHistogram = true)
    
  4. 避免在高频调用方法上使用(性能考虑)

    • 如 getter/setter、循环内方法
  5. 结合通用标签使用

    management:
      metrics:
        tags:
          application: ${spring.application.name}
    

❌ 避免的问题

  1. 重复注解导致重复计数

    @Timed("service.method")
    @Timed("another.timer")  // ❌ 不支持多个 @Timed
    
  2. 在 private 方法上使用(AOP 无法拦截)

    @Timed("private.method")
    private void helper() { }  // ❌ 无效
    
  3. 未启用 AOP

    • 忘记引入 spring-aopaspectjweaver

七、与 Spring Boot Actuator 的集成

Spring Boot 自动配置了:

  • MeterRegistry Bean
  • AOP 基础设施
  • @Counted@Timed 的切面(只要类路径存在)

你只需:

  1. 添加依赖
  2. 使用注解
  3. 访问 /actuator/metrics 查看指标

八、常见问题解答

@Timed@Counted 可以同时使用吗?

可以,会分别创建 Timer 和 Counter。

@Timed("service.process")
@Counted("service.process.invocations")
public void process() { }

❓ 如何自定义异常标签?

默认使用异常类名(如 IllegalArgumentException)。
如需自定义,可通过 MeterFilter 重写:

@Bean
public MeterFilter renameExceptionTag() {
    return MeterFilter.map(id -> {
        String exception = id.getTag("exception");
        if ("IllegalArgumentException".equals(exception)) {
            return id.replaceTag("exception", "validation.error");
        }
        return id;
    });
}

@Timedpercentileshistogram 如何选择?

方式优点缺点推荐场景
percentiles精确内存占用高,不适合高吞吐低频关键接口
publishPercentileHistogram低内存,Prometheus 友好近似值高频接口、生产环境

生产推荐:启用 publishPercentileHistogram = true


九、总结

注解类型适用场景
@CountedCounter调用次数、失败次数统计
@TimedTimer方法耗时、响应时间监控

使用建议:

  • ✅ 优先用于 Service 层Controller 层 的公共方法
  • ✅ 结合 extraTags 添加业务维度
  • ✅ 启用 publishPercentileHistogram 以支持 Prometheus
  • ✅ 避免在 private高频 方法上使用

通过 Micrometer 注解,你可以以极低的成本实现方法级监控,大幅提升应用的可观测性,是构建现代云原生应用的重要工具。


📌 官方文档参考

### WebMvcTagsProvider 的作用 `WebMvcTagsProvider` 是 Spring Boot Actuator 提供的一个接口,用于自定义生成与 HTTP 请求相关的标签(Tags)。这些标签通常用于与指标(Metrics)结合,以帮助监控系统更精确地对请求进行分类和统计。默认情况下,Spring Boot 会基于请求的方法(`method`)、URI(`uri`)和响应状态码(`status`)等信息生成标签。通过自定义 `WebMvcTagsProvider`,可以灵活地添加、修改或过滤这些标签信息,以满足特定的监控需求[^1]。 ### WebMvcTagsProvider 的使用方法 `WebMvcTagsProvider` 接口的实现需要提供一个方法,该方法接收 `HttpServletRequest`、`HttpServletResponse`、`Object`(代表处理请求的控制器方法)和 `Exception`(可能抛出的异常)作为参数,并返回一组 `Tag` 对象。可以通过 `Tags.of(...)` 方法创建标签集合,并通过 `Tag` 的键值对形式添加自定义标签。 自定义 `WebMvcTagsProvider` 的典型步骤如下: 1. 创建一个类或配置方法,返回 `WebMvcTagsProvider` 的实例。 2. 在实现中,通过 `WebMvcTags.uri(request)` 获取当前请求的 URI。 3. 使用 `Tags.of(...)` 构造所需的标签集合。 4. 在 Spring Boot 配置中注册该实例,通常通过 `@Bean` 注解将其声明为一个 Bean。 ### 示例代码 以下是一个完整的 `WebMvcTagsProvider` 自定义实现示例,展示了如何根据请求生成自定义标签: ```java import io.micrometer.core.instrument.Tag; import io.micrometer.core.instrument.Tags; import io.micrometer.webmvc.WebMvcTags; import io.micrometer.webmvc.WebMvcTagsProvider; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerMapping; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @Component public class CustomWebMvcTagsProvider { @Bean public WebMvcTagsProvider webMvcTagsProvider() { return (request, response, handler, e) -> { String uri = WebMvcTags.uri(request); String method = request.getMethod(); int status = response.getStatus(); // 自定义标签:添加 method、uri 和 status return Tags.of( Tag.of("method", method), Tag.of("uri", uri), Tag.of("status", String.valueOf(status)) ); }; } } ``` 在这个示例中,`webMvcTagsProvider` 方法返回了一个自定义的 `WebMvcTagsProvider` 实现。该实现从 `HttpServletRequest` 和 `HttpServletResponse` 中提取了请求的方法、URI 和响应状态码,并将它们封装为 `Tag` 对象集合返回。这些标签随后会被用于指标的记录和监控。 ### 扩展建议 除了基础的 `method`、`uri` 和 `status` 标签外,还可以根据实际需求添加更多自定义标签。例如: - **用户身份标签**:从请求头或会话中提取用户 ID,用于区分不同用户的请求量。 - **设备类型标签**:解析 `User-Agent` 字段,区分移动端和桌面端请求。 - **API 版本标签**:通过 URI 或请求头识别 API 的版本,以便监控不同版本的使用情况。 ```java Tag.of("user", request.getHeader("X-User-ID")), Tag.of("device", isMobile(request) ? "mobile" : "desktop"), Tag.of("api-version", "v1"); ``` 上述扩展标签可以进一步丰富监控数据,使系统能够更精细地分析和优化服务性能。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值