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

