深入了解JMS

806 阅读9分钟

一、JMS基本概念

       JMS(Java message service,Java消息服务)API是一个消息服务的标准/规范,允许应用程序组件基于javaEE平台创建、发送、接收和读取消息。它使分布式通信耦合度更低,消息服务更加可靠以及异步性。

二、JMS消息模型

       JMS消息模型分两种消息通信模型:点到点(point-to-point)(P2P)模型发布/订阅(Pub/Sub)模型。P2P 模型规定了一个消息只能有一个接收者;Pub/Sub 模型允许一个消息可以有多个接收者。简单的讲,点到点模型和发布/订阅模型的区别就是前者是一对一,后者是一对多

  1. 点到点模型 :消息生产者产生一个消息后,把这个消息发送到一个Queue(队列)中,然后消息接收者再从这个Queue中读取,一旦这个消息被一个接收者读取之后,它就在这个Queue中消失了,所以一个消息只能被一个接收者消费。

    1. 概念:
      • 消息队列(Queue)
      • 提供者(Sender)
      • 消费者(Receiver)
    2. 特点:
      • 每个消息有且仅仅只有一个消费者(当有多个消费者时,队列中的一条信息只能随机分配给其中一个消费者,队列中的消息不会被其他消费者重复消费)。
      • 消息的生产者和消费者之间没有时间上的相对性。无论消费者在生产者发送消息的时候是否处于运行状态,它都可以提取消息。
      • 当消费者收到消息的时候,会发送确认收到通知(acknowledgement)
    3. 模式效果图:
  2. 发布/订阅模型: 消息生产者产生一个消息后,把这个消息发送到一个Topic中,这个Topic可以同时有多个接收者在监听,当一个消息到达这个Topic之后,所有接收者都会收到这个消息。

    1. 概念:

      • 主题(Topic)
      • 发布者(Publisher)
      • 订阅者(Subscriber)
    2. 特点:

      • 每个消息可以有多个消费者
      • 生产者和消费者之间有时间上的相关性。订阅一个主题的消费者只能消费他订阅之后生产者发布的消息
      • 为了缓和这样严格的时间相关性,JMS允许客户创建持久订阅,持久订阅允许消费者消费他未处于激活状态时的消息
      • 每条消息都会传送给称为订阅者的多个消息消费者。订阅者有许多类型,包括持久型、非持久型和动态型。
    3. 模式效果图:

三、JMS消息可靠性

       JMS提供了消息持久化、消息应答确认(ACK)、消息事务来保证消息的可靠性(防止消息丢失,消息的重复消费)

  1. 消息持久化: JMS支持两种消息传输模式,此属性可以在session中指定,也可以在发送消息时指定;用来标记此消息是否需要被持久化。

    • PERSISTENT: 表示消息需要被持久化,对于JMS Provider(服务提供者)而言,这种类型的消息将会被存储在磁盘上;以确保在server故障恢复后,消息仍然保留。

    • NON_PERSISTENT: 表示消息不需要持久化,消息有可能被优先存储在内存中,或者存储在磁盘上某个临时文件上;当server故障失效后,消息将不能被恢复。

  2. 消息应答确认: JMS规定了多种应答模式,这些应答模式是保证消息传送的关键所在;服务器确认从JMS生产者接收消息,而JMS消费者确认从服务器接收消息;确认协议允许JMS提供者监测一条消息的整个过程,以便了解是否成功的生产和消费了该消息。JMS主要定义了三种确认模式:

    • AUTO_ACKNOWLEDGE: 当客户成功从receive方法返回的时候,或者从MessageListener.onMessage方法成功返回的时候,会话自动确认客户收到的消息。

    • CLIENT_ACKNOWLEDGE: 为客户端确认,客户端接收到消息后,必须调用javax.jms.Message的acknowledge方法,jms服务器才会删除消息。(默认是批量确认)

    • DUPS_ACKNOWLEDGE: 可重复消息确认,此模式可以允许JMS提供者将一条消息向同一个目的地发送两次以上,也允许批量确认多个消息(消息ID区间)

    注意 : 在非事务性会话中,消息何时被确认取决于创建会话时的应答模式。在事务性会话中,当一个事物被提交的时候,确认自动发生。

  3. 消息事务: JMS 事务遵从发送操作与接收操作相互分离的约定。一组消息要么能够保证全部到达消息服务器,要么一条消息也不能到达消息服务器。

    • JMS事务性发送: 从发送者的角度来看,JMS 提供者为这组消息提供了高速缓存,直到执行 commit() 为止。如果发生了故障,或者执行了 rollback(),这些消息就会丢弃。在一个事务中传送给消息服务器的消息,它并不会转发给消费者,直到该生产者提交该事务为止。

    • JMS事务性接收: 从事务性接收者的角度来看,这些消息会尽可能快地传送给接收者,但是它们一直由 JMS 提供者保存,直到接收者在会话对象上执行 commit() 为止。如果发送了故障,或者执行 rollback(),提供者会试图重新传送消息,在这种情况下,这些消息就会设置重新传送标记。

四、JMS消息消费方式

       在JMS中,消息的产生和消费是异步的。对于消费来说,JMS的消息者可以通过两种方式来消费消息。

  1. 同步消费: 通过调用消费者的receive方法从目的地中显式提取消息。receive方法可以一直阻塞到消息到达。

  2. 异步消费: 客户可以为消费者注册一个消息监听器,以定义在消息到达时所采取的动作。实现MessageListener接口,在MessageListener()方法中实现消息的处理逻辑。

五、JMS基本构件

  1. ConnectionFactory: 连接工厂是客户用来创建连接的对象,例如ActiveMQ提供的ActiveMQConnectionFactory。
  2. Connection: JMS Connection封装了JMS 客户端到JMS Provider 的连接与JMS提供者之间的一个虚拟的连接。
  3. Session: Session是我们操作消息的接口。可以通过session创建生产者、消费者、消息等。Session提供了事务的功能。当我们需要使用session发送/接收多个消息时,可以将这些发送/接收动作放到一个事务中。
  4. MessageProducer: 由Session 对象创建的用来发送消息的对象。
  5. MessageConsumer: 由Session 对象创建的用来接收消息的对象。
  6. Message : 是在消费者和生产者之间传送的对象。一个消息有三个主要部分:
    1. 消息头(必须): JMS消息头预定义了若干字段用于客户端与JMS提供者之间识别和发送消息。
      • JMSDestination : 消息发送的目的地,主要是指Queue和Topic,由session创建而由生产者的send方法设置。
      • JMSDeliveryMode:传送模式:有两种即久模式和非持久模式。一条持久性的消息应该被传输"一次仅仅一次",这就意味着如果JMS提供者出现故障,该消息并不会丢失,它会在服务器恢复之后再次传递。一条非持久的消息最多会传递一次,这意味着服务器出现故障,该消息将永远丢失。由session创建由消息生产者的send方法设置。
      • JMSMessageID:唯一识别每个消息的标识,由JMS消息生产者产生。由send方法设置。
      • JMSTimestamp:一个JMS Provider在调用send()方法时自动设置,它是消息被发送和消费者实际接收的时间差。由客户端设置。
      • JMSCorrelationID:用来连接到另外一个消息,典型的应用是在回复消息中连接到原消息。在大多数情况下,JMSCorrelationID用于将一条消息标记为对JMSMessageID标示的上一条消息的应答,不过,JMSCorrelationID可以是任何值,不仅仅是JMSMessageID。由客户端设置。
      • JMSReplyTo:提供本消息回复消息的目的地址,由客户端设置。
      • JMSRedelivered:如果一个客户端收到一个设置了JMSRedelivered属性的消息,则表示可能客户端曾经在早些时候收到过该消息,但并没有签收(acknowledged)。如果该消息被重新传送,JMSRedelivered=true 否则 JMSRedelivered=flase 。由JMS Provider设置。
      • JMSType:消息类型的标识符,由客户端设置。
      • JMSExpiration:消息过期时间,等于Destination的send方法中的timeToLive值加上发送时刻的GMT的时间值。如果timeToLive值等于零,则JMSExpiration被设置为零,表示该消息永不过期。如果发送后,在消息过期时间之后消息还没有被发送到目的地,则该消息被清除。由send方法设置。
      • JMSPriority:消息优先级,从0-9十个级别,0-4是普通消息,5-9是加急消息。JMS不要求JMS Provider严格按照这十个优先级发送消息,但必须保证加急消息要先于普通消息到达,默认是4级。由send方法设置。
    2. 消息属性: 我们可以给消息设置自定义属性,这些属性主要是提供给应用程序的。对于实现消息过滤功能,消息属性非常有用,JMS API定义了一些标准属性,JMS服务提供者可以选择性的提供部分标准属性。
      • JMSXAppId: application标识。
      • JMSXConsumerTXID: 消息消费者的事务ID,provider自动填充。
      • JMSXDeliveryCount: 消息已重发的次数。
      • JMSXGroupSeq/JMSXGroupID: 消息分组时使用。(JMS要求PRovider必须支持此属性)
      • JMSXProducerTXID: 消息生产者的事务ID
      • JMSXRcvTimestamp: 消息由Provider发送给consumer的时间戳,由Provider填充。
    3. 消息体: JMS允许用户创建五种类型的消息
      • StreamMessage:Java 数据流消息,用标准流操作来顺序的填充和读取。
      • MapMessage:一个Map类型的消息;名称为 string 类型,而值为 Java 的基本类型。
      • TextMessage:普通字符串消息,包含一个String。
      • ObjectMessage:对象消息,包含一个可序列化的Java 对象
      • BytesMessage:二进制数组消息,包含一个byte[]。
      • XMLMessage:一个XML类型的消息。
  7. Destination: 消息发送的目的地,也就是前面说的Queue和Topic。
  8. MessageListener: 消息监听器。如果注册了消息监听器,一旦消息到达,将自动调用监听器的onMessage方法。EJB中的MDB(Message-Driven Bean)就是一种MessageListener。

六、JMS时序图

博主新开通了微信公众号:欢迎关注‘秃顶记’,聪明绝顶走到黑。