Spring Integration消息驱动通道适配器运行数天后停止接收消息求助
你好!看了你的问题描述,这确实是个让人头疼的生产环境问题——迁移到Spring Boot和新版本的Spring Integration后,持久化订阅的消息驱动适配器运行一周左右就“罢工”,重启才能恢复,而且还没报错日志,太磨人了😅。我结合你的场景和Spring Integration的特性,给你梳理几个排查方向和可能的解决方案:
1. 检查JMS连接池的配置有效性
你用的是userCredentialQueueConnectionFactory,首先要确认连接池的参数是否合理。新版本的Spring Integration对JMS连接的管理更严格,若连接池的空闲连接回收策略没配置好,长时间空闲的连接可能失效,但应用没检测到,导致适配器无法接收消息。
- 建议开启连接池的连接有效性检测,比如配置
testOnBorrow或testWhileIdle参数,确保每次获取的连接都是可用的。以Spring的CachedConnectionFactory为例,可以添加如下配置:@Bean public CachedConnectionFactory userCredentialQueueConnectionFactory(ConnectionFactory targetConnectionFactory) { CachedConnectionFactory factory = new CachedConnectionFactory(targetConnectionFactory); factory.setTestConnectionOnBorrow(true); // 借用连接时检测有效性 factory.setCacheConsumers(true); return factory; }
2. 确认持久化订阅的唯一性与状态
你配置了client-id="MySubscriber"和subscription-name="eventEnricherService",这两个参数的组合在JMS Broker中必须是唯一的。如果有旧的连接没正常关闭(比如之前的实例崩溃没清理),Broker可能会认为这个订阅已经被占用,新消息无法投递到当前实例。
- 登录JMS Broker的管理控制台,查看这个持久化订阅的状态:是否处于活跃状态?有没有消息堆积在订阅专属的队列里?如果发现订阅状态异常,可以手动清理旧的订阅实例,再重启应用测试。
3. 监听端点生命周期事件,抓“停止”的原因
既然你怀疑适配器被意外停止,不如直接监听端点的生命周期事件,把状态变化记录到日志里,这样就能知道它什么时候停的、为什么停。
- 添加一个事件监听器组件:
这样只要端点状态变化(不管是停止、启动还是失败),都会有日志记录,帮你定位根因。@Component public class EndpointStatusMonitor implements ApplicationListener<AbstractEndpointEvent> { private static final Logger log = LoggerFactory.getLogger(EndpointStatusMonitor.class); @Override public void onApplicationEvent(AbstractEndpointEvent event) { String endpointName = event.getEndpoint().getComponentName(); log.info("端点 [{}] 状态变更为: {}", endpointName, event.getClass().getSimpleName()); // 如果是失败事件,打印异常栈 if (event instanceof EndpointFailedEvent failedEvent) { log.error("端点 [{}] 运行失败", endpointName, failedEvent.getCause()); } } }
4. 强化Listener Container的错误恢复能力
你的消息驱动适配器配置了error-channel="error-channel-logger",但要确保错误通道的处理逻辑不会吞掉异常,导致Listener Container静默停止。另外,给Listener Container配置自动恢复策略,避免连接断开后无法自动重连。
- 可以自定义
DefaultMessageListenerContainer来精细化配置:
然后在XML配置中引用这个容器:@Bean public DefaultMessageListenerContainer eventEnricherListenerContainer( @Qualifier("userCredentialQueueConnectionFactory") ConnectionFactory connectionFactory, MessageChannel inEventEnricherChannel, MessageChannel errorChannelLogger) { DefaultMessageListenerContainer container = new DefaultMessageListenerContainer(); container.setConnectionFactory(connectionFactory); container.setDestinationName("MyTopic"); container.setPubSubDomain(true); container.setSubscriptionDurable(true); container.setClientId("MySubscriber"); container.setSubscriptionName("eventEnricherService"); container.setMessageListener(new ChannelPublishingJmsMessageListener(inEventEnricherChannel)); container.setErrorChannel(errorChannelLogger); container.setRecoveryInterval(5000); // 每5秒尝试恢复连接 container.setMaxConcurrentConsumers(3); // 多消费者提高容错 container.setAutoStartup(true); return container; }<si-jms:message-driven-channel-adapter id="jmsInEventEnricherAdapter" container="eventEnricherListenerContainer"/>
5. 排查Spring Boot的生命周期管理影响
迁移到Spring Boot后,要注意是否有自动配置的组件(比如Actuator)或外部监控工具误操作了端点状态。比如Actuator的/actuator/integrationgraph端点可以查看所有Spring Integration组件的状态,你可以开启这个端点,定期检查适配器的运行状态。
- 在
application.yml中开启Actuator的集成图形端点:
访问management: endpoints: web: exposure: include: integrationgraph/actuator/integrationgraph就能看到所有端点的状态,确认适配器是否真的被停止了。
6. 检查JMS Broker的日志
不要只看应用日志,JMS Broker的日志里可能藏着关键线索——比如连接断开的原因、消息投递失败的记录、订阅状态变更的日志。比如ActiveMQ会在专属日志中记录持久化订阅的相关操作,你可以重点搜索MySubscriber和eventEnricherService相关的日志内容。
先从这些方向入手排查,应该能找到问题的根源。如果有新的日志或状态信息,也可以补充出来,方便进一步分析!
内容来源于stack exchange

