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

Spring Boot结合Solace动态创建JMS队列监听器异常排查

Spring Boot JMS动态监听器Solace绑定异常解决方案

你在使用Spring Boot+JMS动态创建多队列监听器时,通过Test Container运行Solace容器,出现以下异常,监听器仅偶尔能捕获消息:

10:51:38.633 WARN Setup of JMS message listener invoker failed for destination 'toto' - trying to recover. Cause: SMF AD bind response error [condition = amqp:internal-error]

问题根源分析

  • 重复创建容器工厂:循环中每次调用jmsFactory()生成新的DefaultJmsListenerContainerFactory,每个工厂使用随机clientId,导致Solace收到大量重复/变化的订阅请求,触发内部错误。
  • 持久订阅配置冗余:你监听的是队列(pubSubDomain=false),但设置了setSubscriptionDurable(true),该配置仅适用于主题的持久订阅,队列本身具备持久化特性,此配置会引发不必要的Solace绑定逻辑。
  • 容器工厂未复用:Spring的@Bean方法默认是单例,但循环内直接调用方法会绕过单例机制,创建多个工厂实例,导致资源浪费和配置冲突。

修复方案及代码示例

  1. 移除队列不需要的持久订阅、随机clientId配置,将容器工厂设为单例复用
  2. 在循环外部统一设置容器工厂,所有动态端点共享同一个实例
  3. 优化连接工厂注入方式,符合Spring最佳实践
  4. 添加错误处理器,统一处理监听器异常

修改后的代码:

import lombok.extern.slf4j.Slf4j;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.apache.qpid.jms.JmsConnectionFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.annotation.JmsListenerConfigurer;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
import org.springframework.jms.config.JmsListenerContainerFactory;
import org.springframework.jms.config.JmsListenerEndpointRegistrar;
import org.springframework.jms.config.SimpleJmsListenerEndpoint;
import org.springframework.jms.support.converter.MappingJackson2MessageConverter;
import org.springframework.jms.support.converter.MessageType;
import org.springframework.util.ErrorHandler;

import javax.jms.JMSException;

@Slf4j
@Configuration
public class ListenersConfiguration implements JmsListenerConfigurer {

    private final JmsConnectionFactory connectionFactory;

    // 构造注入替代字段注入,符合Spring最佳实践
    public ListenersConfiguration(JmsConnectionFactory connectionFactory) {
        this.connectionFactory = connectionFactory;
    }

    @Bean
    JmsListenerContainerFactory<?> jmsFactory() {
        DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
        factory.setConnectionFactory(connectionFactory);
        factory.setSessionTransacted(false);
        factory.setPubSubDomain(false);
        
        // 配置消息转换器
        ObjectMapper objectMapper = new ObjectMapper()
                .findAndRegisterModules()
                .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
                .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        MappingJackson2MessageConverter messageConverter = new MappingJackson2MessageConverter();
        messageConverter.setObjectMapper(objectMapper);
        messageConverter.setTargetType(MessageType.TEXT);
        factory.setMessageConverter(messageConverter);
        
        // 添加错误处理器,统一处理异常
        factory.setErrorHandler(error -> log.error("监听器处理异常", error));

        return factory;
    }

    @Override
    public void configureJmsListeners(JmsListenerEndpointRegistrar registrar) {
        // 复用单例容器工厂
        JmsListenerContainerFactory<?> containerFactory = jmsFactory();
        registrar.setContainerFactory(containerFactory);

        dbbRoutes.getRoutes().forEach(route -> {
            SimpleJmsListenerEndpoint endpoint = new SimpleJmsListenerEndpoint();
            endpoint.setId("jms-listener-" + route.getInput()); // 使用有意义的ID便于排查问题
            endpoint.setDestination(route.getInput());
            
            endpoint.setMessageListener(message -> {
                try {
                    log.info("Received ID: {} Destination {}", message.getJMSMessageID(), message.getJMSDestination());
                } catch (JMSException e) {
                    log.error("读取消息异常", e);
                }
            });
            
            registrar.registerEndpoint(endpoint);
        });
    }
}

额外注意事项

  • 确保Solace容器的AMQP端口(默认5672)已正确映射到Test Container
  • 验证目标队列(如toto)已提前创建,或配置Solace允许自动创建队列(需确保连接账号具备对应权限)
  • 若仍有异常,可通过factory.setConcurrency("1-1")设置单线程监听,避免Solace连接过载

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 09:36:10