TL;DR
- 场景: Java 系统做异步解耦与事件驱动,需要统一理解 JMS 的消息模型、对象模型与消息类型
- 结论: JMS 是标准 API(类似 JDBC),关键在 Queue/Topic 语义、Session 与确认/事务边界
- 产出: 一篇可直接落地的 JMS 基础稿:概念—对象模型—消息类型—实现/版本差异速查
版本矩阵
| 项目 | 说明 |
|---|---|
| JMS 2.0 | 属于 Java EE 7,API 仍在 javax.jms 命名空间 |
| Jakarta Messaging 3.1 | 属于 Jakarta EE 10,对应 API 命名空间为 jakarta.jms |
| ActiveMQ Classic | 完整支持 JMS 1.1 |
| ActiveMQ Artemis | 基于自身协议实现,提供客户端侧 JNDI |
| RabbitMQ | 本身不是 JMS Provider,需要配套插件 |
JMS模式
基本介绍
JMS(Java Message Service)是Java平台提供的一套标准API,专门用于实现面向消息中间件(MOM)的编程接口。
核心特点:
- 跨平台性: JMS提供与具体实现无关的抽象接口
- 松耦合通信: 通过消息代理实现生产者和消费者的解耦
- 支持两种消息模型:
- 点对点(Point-to-Point): 基于队列(Queue)
- 发布/订阅(Publish/Subscribe): 基于主题(Topic)
JMS 消息
JMS 报文头全部字段:
- JMSMessageID
- JMSDestination
- JMSDeliveryMode
- JMSExpiration
- JMSPriority
- JMSTimestamp
- JMSCorrelationID
- JMSReplyTo
- JMSType
- JMSRedelivered
6 种标准消息类型:
- TextMessage: 最常用的消息类型,包含普通字符串内容
- ObjectMessage: 包含一个可序列化的Java对象
- MapMessage: 包含一组键值对数据
- BytesMessage: 包含未解释的字节流数据
- StreamMessage: 包含一系列Java基本类型的流数据
- Message: 不包含实际数据,仅包含消息头和属性
体系架构
JMS由以下元素组成:
- JMS Provider: JMS接口的一个实现
- JMS Client: 生产或者消费消息的Java应用程序
- JMS Producer: 创建并发送消息的JMS客户
- JMS Consumer: 接收消息的JMS客户
- JMS Message: 在JMS客户之间传递的数据对象
- JMS Queue: 缓存消息的容器
- JMS Topic: Pub/Sub模式
对象模型
Connection Factory
连接工厂是JMS中一个重要的被管对象,负责创建和管理与JMS提供者之间的连接:
ConnectionFactory cf = (ConnectionFactory)ctx.lookup("ConnectionFactory");
Connection connection = cf.createConnection();
Session
表示一个单线程的上下文,用于发送和接收消息:
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer
MessageProducer 是 JMS 中用于发送消息的核心接口:
MessageProducer producer = session.createProducer(destination);
producer.send(message);
MessageConsumer
MessageConsumer 是 JMS 中的核心接口之一,代表消息消费者:
同步接收:
Message message = consumer.receive();
Message message = consumer.receive(5000);
异步接收:
consumer.setMessageListener(new MessageListener() {
@Override
public void onMessage(Message message) {
// 处理消息
}
});
错误速查
| 症状 | 根因 | 修复 |
|---|---|---|
NoClassDefFoundError: javax/jms/... | 依赖命名空间不匹配 | 统一到一套 API |
| Topic 订阅收不到历史消息 | 非持久订阅只接收订阅后消息 | 使用 durable subscription |
| 消费者一直阻塞 | 未调用 connection.start() | 按正确顺序调用 |
| 重复消费 | ACK/事务边界不正确 | 开启事务并成功 commit |
| 消息顺序不稳定 | 多消费者并发、预取导致乱序 | 需要强顺序:单 consumer |
ObjectMessage 反序列化失败 | 消费端缺少同名类 | 使用 TextMessage(JSON) |