第二章 基于 JMS 的消息传送
2-1 Java 消息队列 JMS 整体设计结构
基本要素
- 生产者 producer
- 消费者 consumer
- 消息服务 broker 交互模型
2-2 JMS 两种消息传送模式
- 点对点( Point-to-Point):专门用于使用队列 Queue 传送消息;
- 发布/订阅(Publish/Subscribe):专门用于使用主题 Topic 传送消息。
基于队列 Queue 的点对点消息只能被一个消费者消费,如多个消费 者都注册到同一个消息队列上, 当生产者发送一条消息后, 而只有其 中一个消费者会接收到该消息,而不是所有消费者都能接收到该消息。
基于主题的发布与订阅消息能被多个消费者消费,生产者发送的消息,所有订阅了该 topic 的消费者都能接收到。
2-3 Java 消息队列 JMS API 总体概览
JMS API 概览
JMS API 可以分为3 个主要部分:
- 公共 API:可用于向一个队列或主题发送消息或从其中接收消息;
- 点对点 API:专门用于使用队列 Queue 传送消息;
- 发布/订阅 API:专门用于使用主题 Topic 传送消息。
JMS 公共 API
在 JMS 公共 API 内部, 和发送与接收消息有关的 JMS API 接口主要是:
- ConnectionFactory
- Connection
- Session
- Message
- Destination
- MessageProducer
- MessageConsumer
它们的关系是 :一旦有了ConnectionFactory ,就可以创建 Connection,一旦有了 Connection,就可以创建 Session,而一旦 有了 Session ,就可以创建 Message 、MessageProducer 和MessageConsumer。
JMS 点对点 API
点对点 (p2p) 消息传送模型 API 是指JMS API 之内基于队列 (Queue)的接口:
- QueueConnectionFactory
- QueueConnection
- QueueSession
- Message
- Queue
- QueueSender
- QueueReceiver
从接口的命名可以看出,大多数接口名称仅仅是在公共 API 接口名称 之前添加 Queue 一词。一般来说, 使用点对点消息传送模型的应用 程序将使用基于队列的 API,而不使用公共 API 。
JMS 发布/订阅 API
发布/订阅消息传送模型 API 是指JMS API 之内基于主题(Topic)的接口:
- TopicConnectionFactory
- TopicConnection
- TopicSession
- Message
- Topic
- TopicPublisher
- TopicSubscriber
由于基于主题(Topic)的 JMS API 类似于基于队列(Queue) 的API ,因此在大多数情况下,Queue 这个词会由 Topic 取代。
2-4 ActiveMQ 点对点发送示例
1、加入 jms 和 activemq 的相关 jar 包
<!-- JMS规范的jar依赖 -- >
<dependency>
<groupId>javax.jms</groupId>
<artifactId>javax.jms-api</artifactId>
<version>2.0.1</version>
</dependency>
<!-- activeMQ对jms具体实现的jar依赖 -- >
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-client</artifactId>
<version>5.15.2</version>
</dependency>
2、参考样例代码编写一个消费发送者 和 一个消息接收者
3、运行发送者和接收者的代码, 在 activeMQ 的 web 控制台观察消息数据
2-5 ActiveMQ 发布与订阅示例
1、加入 jms 和 activemq 的相关 jar 包
2、参考样例代码编写一个消费发布者 和 一个消息订阅者
3、运行发布者和订阅者的代码, 在 activeMQ 的 web 控制台观察消 息数据 注意:消息订阅者需要先运行,然后再运行消息发布者
2-6 Queue 与 Topic 比较
拉模式与推模式
点对点消息, 如果没有消费者在监听队列, 消息将保留在队列中,直 至消息消费者连接到队列为止。在这种模型中, 消息不是自动推动给 消息消费者的, 而是要由消息消费者从队列中请求获得 (拉模式)。
pub/sub 消息传递模型基本上是一个推模型。在该模型中,消息会 自动广播,消息消费者无须通过主动请求或轮询主题的方法来获得新的消息。
2-7 ActiveMQ 消息类型
- **TextMessage 文本消息:**携带一个 java.lang.String 作为有效数 据(负载)的消息,可用于字符串类型的信息交换;
- **ObjectMessage 对象消息:**携带一个可以序列化的 Java 对象作为有效负载的消息,可用于 Java对象类型的信息交换;
- **MapMessage 映射消息:**携带一组键值对的数据作为有效负载 的消息, 有效数据值必须是 Java 原始数据类型(或者它们的包装类) 及 String。即:byte, short, int, long, float, double, char, boolean, String
- **BytesMessage 字节消息 :**携带一组原始数据类型的字节流作 为有效负载的消息;
- **StreamMessage 流消息:**携带一个原始数据类型流作为有效负载的消息,它保持了写入流时的数据类型,写入什么类型,则读取也 需要是相同的类型
2-8 ActiveMQ 事务消息和非事务消息
消息分为事务消息和非事务消息;
**事务消息:**创建会话 Session 使用transacted=true
connection.createSession(Boolean.TRUE,
Session.AUTO_ACKNOWLEDGE);
**非事务消息:**创建会话 Session 使用 transacted=false
connection.createSession(Boolean.FALSE,
Session.AUTO_ACKNOWLEDGE);
事务消息必须在发送和接收完消息后显式地调用 session.commit();
2-9 ActiveMQ 消息确认机制
消息只有在被确认之后, 才认为已经被成功消费, 然后消息才会从队列或主题中删除。
消息的成功消费通常包含三个阶段:
(1)、客户接收消息;
(2)、客户处理消息;
(3)、消息被确认;
- Session.AUTO_ACKNOWLEDGE ;客户(消费者) 成功从receive 方法返回时,或者从 MessageListener.onMessage 方法成功返回时,会话自动确认消息。
- Session.CLIENT_ACKNOWLEDGE;客户通过显式调用消息的 acknowledge 方法确认消息。
- Session.DUPS_OK_ACKNOWLEDGE;不是必须确认,是一种“懒散的”消息确认,消息可能会重复发送,在第二次重新传送消息时 ,消息头的 JMSRedelivered 会被置为 true 标识当前消息已经传送过一次,客户端需要进行消息的重复处理控制。
- Session.SESSION_TRANSACTED;事务提交并确认。如果是事务性消息,不管设置何种消息确认模式,都会自动被确认。
2-10 ActiveMQ 持久化消息与非持久化消息
//设置发送的消息是否需要持久化
//不持久化
messageProducer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
//持久化的,当然 activemq 发送消息默认都是持久化的
messageProducer.setDeliveryMode(DeliveryMode.PERSISTENT);
2-11 ActiveMQ 消息过滤
ActiveMQ 提供了一种机制, 可根据消息选择器中的标准来执行消息过滤,只接收符合过滤标准的消息;
生产者可在消息中放入特有的标志,而消费者使用基于这些特定的标志来接收消息; 1、发送消息放入特殊标志:
message.setStringProperty(name, value);
2、接收消息使用基于特殊标志的消息选择器:
MessageConsumer createConsumer(Destination destination, String messageSelector);
注:消息选择器是一个字符串,语法与数据库的 SQL 相似,相当于SQL 语句 where 条件后面的内容
2-12 ActiveMQ 消息接收方式
同步接收
receive()方法接收消息叫同步接收;
同步接收相当于是只有一个线程在接收
异步接收
使用监听器 MessageListener 接收消息 ,这种接收方式叫异步接收.
注意: 在同一个 consumer 中,我们不能同时使用这 2 种风格;
比如在使用 listener 的情况下, 当调用 receive()方法将会抛出一个 Exception;