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

Quarkus环境下如何无反射获取ActiveMQ Classic客户端统计指标对接Micrometer?

问题描述

我们有一个基于Quarkus(未使用smallrye-messaging)、Java 17构建的应用,使用org.apache.activemq:activemq-client:6.1.3连接ActiveMQ Classic broker。需要将客户端收集的生产者和消费者指标(如发送/接收字节数)暴露给Micrometer,再同步至Grafana。

目前能在调试器中查看各类统计数据,但无法通过JMS 2.0实现类(如实现JMSProducer的ActiveMQProducer)直接查询这些统计信息,只能通过反射实现指标采集(代码如下),但该实现复杂且易因底层代码变更失效,希望找到无需反射的方式或现成工具库替代:

public static void instrumentProducer(JMSProducer producer) {
    if (!(producer instanceof ActiveMQProducer amqProducer)) {
      throw new IllegalArgumentException("Expected an instance of ActiveMQProducer, but got: " + producer.getClass());
    }

    /* Is there a way to do this without reflection? */
    var field = Arrays.stream(ActiveMQProducer.class.getDeclaredFields())
            .filter(f -> ActiveMQMessageProducer.class.isAssignableFrom(f.getType()))
            .findFirst()
                    .orElseThrow(() -> new NoSuchElementException("Could not find ActiveMQMessageProducer field to scrape metrics from"));

    try {
      field.trySetAccessible();
      var messageProducer = (ActiveMQMessageProducer) field.get(amqProducer);
      messageProducer.getStats().setEnabled(true);
      var messageCount = messageProducer.getProducerStats().getMessageCount();

      // Ideally this should be a counter, but I'll figure that out.
      Gauge.builder("activemq.producer.message.count", messageCount::getCount)
          .baseUnit(messageCount.getUnit())
          .description(messageCount.getDescription())
          .register(globalRegistry);
    } catch (IllegalAccessException e) {
      throw new RuntimeException("Unable to instrument JMSProducer", e);
    }
  }
解决方案

1. 直接获取ActiveMQMessageProducer(无需反射)

ActiveMQ的ActiveMQProducer是JMS 2.0 JMSProducer的包装类,你可以跳过JMS标准API,直接通过ActiveMQSession创建或获取ActiveMQMessageProducer,这样就能直接访问统计对象:

// 假设已持有ActiveMQSession实例
ActiveMQMessageProducer messageProducer = (ActiveMQMessageProducer) session.createProducer(destination);
// 启用统计收集
messageProducer.getStats().setEnabled(true);

// 直接注册Micrometer指标
Gauge.builder("activemq.producer.message.count", messageProducer.getProducerStats().getMessageCount()::getCount)
    .baseUnit("messages")
    .description("Total number of messages sent by this producer")
    .register(globalRegistry);

如果是从JMSContext获取的JMSProducer,可以先将JMSContext强转为ActiveMQJMSContext,再拿到内部的ActiveMQSession:

ActiveMQJMSContext amqContext = (ActiveMQJMSContext) jmsContext;
ActiveMQSession amqSession = amqContext.getSession();
// 后续步骤同上,直接操作ActiveMQMessageProducer

2. 利用ActiveMQ连接级全局统计

ActiveMQ Classic客户端的ActiveMQConnection支持全局统计开关,开启后会自动收集所有生产者、消费者的统计数据,无需逐个处理实例:

ActiveMQConnection connection = (ActiveMQConnection) jmsConnection;
connection.setStatsEnabled(true);

// 注册全局生产者消息数指标
Gauge.builder("activemq.global.producer.message.count", connection.getProducerStats()::getMessageCount)
    .baseUnit("messages")
    .description("Total number of messages sent by all producers")
    .register(globalRegistry);

3. 封装自定义Micrometer MeterBinder

基于Micrometer的MeterBinder接口封装ActiveMQ统计逻辑,统一管理指标注册,提升代码可维护性:

public class ActiveMQProducerMeterBinder implements MeterBinder {
    private final ActiveMQMessageProducer producer;

    public ActiveMQProducerMeterBinder(ActiveMQMessageProducer producer) {
        this.producer = producer;
        producer.getStats().setEnabled(true);
    }

    @Override
    public void bindTo(MeterRegistry registry) {
        ProducerStats stats = producer.getProducerStats();
        // 注册消息数指标
        Gauge.builder("activemq.producer.message.count", stats.getMessageCount()::getCount)
            .baseUnit("messages")
            .description("Total messages sent by producer")
            .register(registry);
        // 注册字节数指标
        Gauge.builder("activemq.producer.byte.count", stats.getByteCount()::getCount)
            .baseUnit("bytes")
            .description("Total bytes sent by producer")
            .register(registry);
    }
}

// 使用示例
new ActiveMQProducerMeterBinder(messageProducer).bindTo(globalRegistry);

核心思路总结

  • 优先使用ActiveMQ原生API(而非JMS标准API)获取客户端实例,直接访问统计方法
  • 确保启用统计开关(setStatsEnabled(true)),保证数据被正常收集
  • 基于Micrometer标准接口封装指标逻辑,避免重复代码,降低维护成本

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 17:49:51