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

Spring Cloud Sleuth集成JMS启动报错及手动集成Brave方法问询

问题描述

我正在开发一个基于Java消息服务(JMS)的项目,采用ActiveMQ连接工厂实现。现在希望通过spring-cloud-starter-sleuth进行链路追踪埋点,但启动应用时抛出以下异常:

org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.apache.activemq.pool.PooledConnectionFactory]: Factory method 'pooledConnectionFactory' threw exception; nested exception is java.lang.IllegalStateException: @Bean method JmsConfiguration.senderActiveMQConnectionFactory called as bean reference for type [org.apache.activemq.ActiveMQConnectionFactory] but overridden by non-compatible bean instance of type [org.springframework.cloud.sleuth.instrument.messaging.LazyTopicConnectionFactory]. Overriding bean of same name declared in: class path resource [com/demo/appconfig/JmsConfiguration.class]

我的连接工厂Bean配置代码如下:

// ***** sender configuration
@Bean
public ActiveMQConnectionFactory senderActiveMQConnectionFactory() {
    ActiveMQConnectionFactory activeMQConnectionFactory =
            new ActiveMQConnectionFactory();
    activeMQConnectionFactory.setBrokerURL(brokerUrl);
    activeMQConnectionFactory.setUseAsyncSend(useAsyncSend);
    return activeMQConnectionFactory;
}  

@Bean
public PooledConnectionFactory pooledConnectionFactory() {
    return new org.apache.activemq.pool.PooledConnectionFactory(
            senderActiveMQConnectionFactory());
}

@Bean
public JmsTemplate jmsTemplate() {
    JmsTemplate jmsTemplate = new JmsTemplate(pooledConnectionFactory());
    jmsTemplate.setMessageConverter(messageConverter());
    return jmsTemplate;
}

我尝试了spring-cloud-starter-sleuth的所有发布版本及最新版本,问题依旧,该如何解决?

更新:
根据相关GitHub issue评论,需要禁用Sleuth自动配置的JMS追踪,再按照Brave文档手动埋点连接,但我从Brave文档中无法获取足够实操信息,请问在Spring Boot应用中如何手动集成Brave埋点?


解决方案

第一步:解决启动Bean冲突问题

先通过配置关闭Sleuth对JMS的自动代理,避免Bean类型冲突:
在application.properties中添加:

spring.sleuth.messaging.jms.enabled=false

或YAML格式:

spring:
  sleuth:
    messaging:
      jms:
        enabled: false

第二步:手动集成Brave实现JMS链路追踪

1. 引入依赖

在项目构建文件中添加Brave的JMS instrumentation依赖:

Maven(pom.xml)

<dependency>
    <groupId>io.zipkin.brave</groupId>
    <artifactId>brave-instrumentation-jms</artifactId>
    <version>最新稳定版</version>
</dependency>
<dependency>
    <groupId>io.zipkin.reporter2</groupId>
    <artifactId>zipkin-reporter-brave</artifactId>
    <version>最新稳定版</version>
</dependency>

Gradle(build.gradle)

implementation 'io.zipkin.brave:brave-instrumentation-jms:最新稳定版'
implementation 'io.zipkin.reporter2:zipkin-reporter-brave:最新稳定版'

2. 配置Brave核心组件

创建Brave的追踪核心Bean,对接Zipkin服务:

import brave.Tracing;
import brave.sampler.Sampler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import zipkin2.reporter.AsyncReporter;
import zipkin2.reporter.Sender;
import zipkin2.reporter.okhttp3.OkHttpSender;

@Configuration
public class BraveConfig {

    // 配置Zipkin服务地址
    @Bean
    public Sender zipkinSender() {
        return OkHttpSender.create("http://你的Zipkin地址:9411/api/v2/spans");
    }

    @Bean
    public AsyncReporter<zipkin2.Span> asyncReporter(Sender sender) {
        return AsyncReporter.create(sender);
    }

    @Bean
    public Tracing tracing(AsyncReporter<zipkin2.Span> reporter) {
        return Tracing.newBuilder()
                .localServiceName("你的服务名称")
                .sampler(Sampler.ALWAYS_SAMPLE) // 生产环境可调整采样策略
                .spanReporter(reporter)
                .build();
    }

    @Bean
    public brave.Tracer tracer(Tracing tracing) {
        return tracing.tracer();
    }
}

3. 包装JMS连接工厂

修改原有JMS配置,用Brave包装连接工厂,实现生产者链路埋点:

import brave.jms.JmsTracing;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.pool.PooledConnectionFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.core.JmsTemplate;

@Configuration
public class JmsConfiguration {

    private final String brokerUrl = "tcp://你的ActiveMQ地址:61616";
    private final boolean useAsyncSend = true;

    // 原始连接工厂(不暴露为Bean,避免被代理)
    private ActiveMQConnectionFactory rawConnectionFactory() {
        ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory();
        factory.setBrokerURL(brokerUrl);
        factory.setUseAsyncSend(useAsyncSend);
        return factory;
    }

    // 用Brave包装后的连接工厂
    @Bean
    public ActiveMQConnectionFactory senderActiveMQConnectionFactory(JmsTracing jmsTracing) {
        return (ActiveMQConnectionFactory) jmsTracing.connectionFactory(rawConnectionFactory());
    }

    @Bean
    public PooledConnectionFactory pooledConnectionFactory(ActiveMQConnectionFactory connectionFactory) {
        return new PooledConnectionFactory(connectionFactory);
    }

    @Bean
    public JmsTemplate jmsTemplate(PooledConnectionFactory pooledConnectionFactory) {
        JmsTemplate template = new JmsTemplate(pooledConnectionFactory);
        template.setMessageConverter(messageConverter());
        return template;
    }

    @Bean
    public JmsTracing jmsTracing(brave.Tracer tracer) {
        return JmsTracing.create(tracer);
    }

    // 保留原有MessageConverter配置
    // @Bean
    // public MessageConverter messageConverter() { ... }
}

4. 消费者端链路埋点

为@JmsListener配置包装后的容器工厂,实现消费链路追踪:

import brave.jms.JmsTracing;
import org.springframework.context.annotation.Bean;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
import org.springframework.jms.config.JmsListenerContainerFactory;

@Configuration
public class JmsListenerConfig {

    @Bean
    public JmsListenerContainerFactory<?> jmsListenerContainerFactory(
            PooledConnectionFactory pooledConnectionFactory, JmsTracing jmsTracing) {
        DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
        factory.setConnectionFactory(jmsTracing.connectionFactory(pooledConnectionFactory));
        factory.setConcurrency("1-5"); // 保留原有并发配置
        return factory;
    }
}

消费者类保持原有@JmsListener注解即可:

import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;

@Component
public class JmsConsumer {

    @JmsListener(destination = "你的队列名称", containerFactory = "jmsListenerContainerFactory")
    public void consumeMessage(String message) {
        // 业务逻辑实现
    }
}

验证

启动应用后发送JMS消息,查看Zipkin控制台,即可看到生产者与消费者的完整链路信息。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 06:39:13