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

Quarkus:如何为Timed注解的double[]类型percentiles参数配置YAML值

解决Quarkus中Timed注解percentiles参数从YAML配置读取的问题

因为@Timed注解的percentiles是double[]类型,直接用${}表达式赋值不被原生支持,这里提供两种可行方案:

方案一:使用编程式Timer替代注解

放弃注解方式,通过代码从配置读取百分位数,手动创建并使用Timer:

  1. 在application.yaml中配置百分位数:
percentile:
  default:
    setting: 0.90,0.95
  1. 创建配置类绑定该参数:
import io.smallrye.config.ConfigMapping;
import java.util.List;

@ConfigMapping(prefix = "percentile.default")
public interface PercentileConfig {
    List<Double> setting();
}
  1. 在业务类中注入配置,编程式创建Timer:
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import org.eclipse.microprofile.metrics.MetricRegistry;
import org.eclipse.microprofile.metrics.Timer;
import org.eclipse.microprofile.metrics.annotation.RegistryType;
import java.util.concurrent.TimeUnit;

@ApplicationScoped
public class YourBusinessService {
    @Inject
    PercentileConfig percentileConfig;

    @Inject
    @RegistryType(type = MetricRegistry.Type.APPLICATION)
    MetricRegistry registry;

    public void targetMethod() {
        // 将配置的List转为double数组
        double[] percentiles = percentileConfig.setting()
                .stream()
                .mapToDouble(Double::doubleValue)
                .toArray();

        // 创建带指定百分位数的Timer
        Timer timer = registry.timer("some_metric",
                Timer.builder()
                        .percentiles(percentiles)
                        .build());

        // 用Timer包裹业务逻辑
        try (Timer.Context ignored = timer.time()) {
            // 你的业务代码逻辑
        }
    }
}

方案二:自定义注解+拦截器实现动态配置

如果想保留注解风格,可以自定义注解,结合拦截器读取配置并处理Timer逻辑:

  1. 自定义注解:
import jakarta.interceptor.InterceptorBinding;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@InterceptorBinding
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ConfigurableTimed {
    String value(); // 指标名称
    String percentilesKey(); // 配置文件中的键名
}
  1. 创建拦截器实现:
import jakarta.annotation.Priority;
import jakarta.inject.Inject;
import jakarta.interceptor.AroundInvoke;
import jakarta.interceptor.Interceptor;
import jakarta.interceptor.InvocationContext;
import org.eclipse.microprofile.config.Config;
import org.eclipse.microprofile.metrics.MetricRegistry;
import org.eclipse.microprofile.metrics.Timer;
import org.eclipse.microprofile.metrics.annotation.RegistryType;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;

@Interceptor
@ConfigurableTimed(value = "", percentilesKey = "")
@Priority(Interceptor.Priority.APPLICATION)
public class ConfigurableTimedInterceptor {
    @Inject
    Config config;

    @Inject
    @RegistryType(type = MetricRegistry.Type.APPLICATION)
    MetricRegistry registry;

    @AroundInvoke
    public Object invoke(InvocationContext ctx) throws Exception {
        ConfigurableTimed annotation = ctx.getMethod().getAnnotation(ConfigurableTimed.class);
        String metricName = annotation.value();
        String configKey = annotation.percentilesKey();

        // 读取配置并转为double数组
        String percentilesStr = config.getValue(configKey, String.class);
        double[] percentiles = Arrays.stream(percentilesStr.split(","))
                .map(String::trim)
                .mapToDouble(Double::parseDouble)
                .toArray();

        // 创建Timer并执行业务逻辑
        Timer timer = registry.timer(metricName,
                Timer.builder()
                        .percentiles(percentiles)
                        .build());

        try (Timer.Context ignored = timer.time()) {
            return ctx.proceed();
        }
    }
}
  1. 在业务方法上使用自定义注解:
@ApplicationScoped
public class YourBusinessService {
    @ConfigurableTimed(value = "some_metric", percentilesKey = "percentile.default.setting")
    public void targetMethod() {
        // 你的业务代码逻辑
    }
}
  1. 保持application.yaml中的配置不变:
percentile:
  default:
    setting: 0.90,0.95

补充说明

  • 方案一更直接,适合不需要大量复用注解的场景;方案二更贴近原生注解体验,适合多个方法需要统一配置逻辑的场景。
  • 确保Quarkus依赖中包含quarkus-smallrye-metrics扩展,否则相关Metrics API无法使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 17:53:18