大家好,我是G探险者!
本文带你深入理解 Spring 框架中两种最常用的 JMS 消息监听容器:
SimpleMessageListenerContainer与DefaultMessageListenerContainer,并通过实战告诉你如何优雅、安全、稳定地监听 MQ 消息。
🧠 背景说明
在使用 ActiveMQ、IBM MQ、TongLinkQ 等消息中间件时,Spring 提供了两种强大的消息监听容器:
SimpleMessageListenerContainer(简称:SMLC)DefaultMessageListenerContainer(简称:DMLC)
虽然它们都能接收 MQ 消息,但差别极大,使用不当会导致:
- 监听不到消息
- 自动重连无效
- 无法控制线程并发
- MQ重启后容器崩溃等
📦 一、核心对比一览表
| 特性 | SimpleMessageListenerContainer | DefaultMessageListenerContainer |
|---|---|---|
| 线程模型 | 启动时创建固定数量线程 | 支持动态线程调度 |
| 并发控制 | setConcurrentConsumers() 固定 | setMaxConcurrentConsumers() 支持动态扩容 |
| 自动重连 | ❌ 不具备 | ✅ 内建重连机制 |
| Session 事务支持 | 基础支持 | ✅ 更完整的事务控制 |
| 配置复杂度 | 简单 | 稍复杂 |
| 使用场景 | 简单监听、性能高 | 企业场景、需高可用重连能力 |
📌 二、典型使用示例
✅ 1. 使用 SimpleMessageListenerContainer
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.setDestinationName("MY.QUEUE");
container.setMessageListener(new MyMessageListener());
container.setConcurrentConsumers(5); // 固定并发线程数
container.setSessionAcknowledgeMode(Session.AUTO_ACKNOWLEDGE);
container.start();
特点:
- 易用,启动即监听
- 不支持自动重连,MQ 挂了需要重启容器
- 不适合生产高可用场景
✅ 2. 使用 DefaultMessageListenerContainer
DefaultMessageListenerContainer container = new DefaultMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.setDestinationName("MY.QUEUE");
container.setMessageListener(new MyMessageListener());
container.setConcurrentConsumers(5);
container.setMaxConcurrentConsumers(10); // 动态扩容
container.setRecoveryInterval(5000); // 重连间隔
container.setSessionAcknowledgeMode(Session.AUTO_ACKNOWLEDGE);
container.afterPropertiesSet(); // ⚠️ 必须调用
container.start();
特点:
- 支持自动重连:MQ 重启后会自动尝试恢复连接
- 支持事务:可通过
setSessionTransacted(true)启用事务 - 配置项多,但适合生产使用
🚨 三、常见问题与解决
❓ DefaultMessageListenerContainer 无法监听到消息?
✅ 检查是否调用了 afterPropertiesSet(),这是它内部初始化监听线程的必要步骤。
container.afterPropertiesSet(); // 初始化监听线程池
container.start();
❓ MQ 挂了,监听容器崩了?
- 使用
DefaultMessageListenerContainer - 配置自动重连间隔
setRecoveryInterval(5000) - 保证底层的连接工厂(如 IBM MQ)也配置了重连参数,如:
connectionFactory.setIntProperty(WMQConstants.WMQ_CLIENT_RECONNECT_OPTIONS,
WMQConstants.WMQ_CLIENT_RECONNECT);
🔁 四、消息确认与事务模式
JMS 支持的确认模式:
| 模式 | 含义 |
|---|---|
AUTO_ACKNOWLEDGE | 自动确认,消息一旦处理即确认 |
CLIENT_ACKNOWLEDGE | 程序手动调用 message.acknowledge() |
DUPS_OK_ACKNOWLEDGE | 延迟确认,允许重复消息 |
SESSION_TRANSACTED | 开启事务,使用 commit()/rollback() 控制确认 |
如何开启事务:
container.setSessionTransacted(true); // 启用事务
container.setSessionAcknowledgeMode(Session.SESSION_TRANSACTED);
🛠 五、实战建议
| 场景 | 推荐容器 |
|---|---|
| Demo、小规模测试 | SimpleMessageListenerContainer |
| 生产环境 / MQ 容灾 | ✅ DefaultMessageListenerContainer |
| 多线程并发监听 | 两者皆可,DMLC 支持动态伸缩更优秀 |
| 强一致性要求 | DMLC + JMS事务机制 |
🧵 六、如何优雅关闭监听容器?
container.stop(); // 停止监听线程
建议结合应用生命周期使用 @PreDestroy 关闭监听,避免服务重启或部署时消息丢失。
✅ 七、结语
Spring JMS 为我们封装了强大的消息监听容器。其中:
SimpleMessageListenerContainer轻量好用DefaultMessageListenerContainer适合容灾高可用场景真正的企业级 MQ 应用,应以 容器 + 自动重连 + 可监控 + 容灾保护 为基准线。
下一篇我们将聚焦:
📘 《如何在Spring中实现MQ消息的自动重连:监听与发送双通道策略》