JMS简介

什么是JMS

Java消息服务(Java Message Service,简称JMS)是用于访问企业消息系统的开发商中立的API。企业消息系统可以协助应用软件通过网络进行消息交互。JMS在其中扮演的角色与JDBC很相似,正如JDBC提供了一套用于访问各种不同关系数据库的公共API,JMS也提供了独立于特定厂商的企业消息系统访问方式。

使用JMS的应用程序被称为JMS客户端,处理消息路由与传递的消息系统被称为JMS Provider,而JMS应用则是由多个JMS客户端和一个JMS Provider构成的业务系统。发送消息的JMS客户端被称为生产者(producer),而接收消息的JMS客户端则被称为消费者(consumer)。同一JMS客户端既可以是生产者也可以是消费者。

JMS的编程过程很简单,概括为:应用程序A发送一条消息到消息服务器(也就是JMS Provider)的某个目得地(Destination),然后消息服务器把消息转发给应用程序B。因为应用程序A和应用程序B没有直接的代码关连,所以两者实现了解耦。

消息的结构

1. 头(head)

每条JMS 消息都必须具有消息头。头字段包含用于路由和识别消息的值。可以通过多种方式来设置消息头的值:
a. 由JMS 提供者在生成或传送消息的过程中自动设置
b. 由生产者客户机通过在创建消息生产者时指定的设置进行设置
c. 由生产者客户机逐一对各条消息进行设置

2. 属性(property)

消息可以包含称作属性的可选头字段。他们是以属性名和属性值对的形式制定的。可以将属性是为消息头得扩展,其中可以包括如下信息:创建数据的进程、数据的创建时间以及每条数据的结构。JMS提供者也可以添加影响消息处理的属性,如是否应压缩消息或如何在消息生命周期结束时废弃消息。

3. 主体(body)

包含要发送给接收应用程序的内容。每个消息接口特定于它所支持的内容类型。JMS为不同类型的内容提供了他们各自的消息类型,但是所有消息都派生自Message接口。
StreamMessage 一种主体中包含Java基元值流的消息。其填充和读取均按顺序进行。
MapMessage 一种主体中包含一组键--值对的消息。没有定义条目顺序。
TextMessage 一种主体中包含Java字符串的消息(例如,XML消息)。
ObjectMessage 一种主体中包含序列化Java对象的消息。
BytesMessage 一种主体中包含连续字节流的消息。
例如:MapMessage 消息格式

MapMessage={  
    Header={  
        ... standard headers ...  
        CorrelationID={123-00001}  
    }  
    Properties={  
        AccountID={Integer:1234}  
    }  
    Fields={  
        Name={String:Mark}  
        Age={Integer:47}  
    }   
} 

消息的传递模型

JMS支持两种消息传递模型:点对点(point-to-point,简称PTP)和发布/订阅(publish/subscribe,简称pub/sub)。这两种消息传递模型非常相似,但有以下区别:
a. PTP消息传递模型规定了一条消息之恩能够传递费一个接收方。
b. Pub/sub消息传递模型允许一条消息传递给多个接收方
每个模型都通过扩展公用基类来实现。例如:javax.jms.Queue和Javax.jms.Topic都扩展自javax.jms.Destination类。

1. 点对点消息传递

通过点对点的消息传递模型,一个应用程序可以向另外一个应用程序发送消息。在此传递模型中,目标类型时队列。消息首先被传送至队列目标,然后从该队列将消息传送至对此队列进行监听的某个消费者。
一个队列可以关联多个队列发送方和接收方,但一条消息仅传递给一个接收方。如果多个接收方正在监听队列上的消息,JMS Provider将根据“先来者优先”的原则确定由哪个消费方接受下一条消息。如果没有接收方在监听队列,消息将保留在队列中,直至接收方连接到队列为止。这种消息传递模型是传统意义上的拉模型或轮询模型。在此列模型中,消息不是自动推动给客户端的,而是要由客户端从队列中请求获得。

2. 发布/订阅消息传递

通过发布/订阅消息传递模型,应用程序能够将一条消息发送到多个接收方。在此传送模型中,目标类型是主题。消息首先被传送至主题目标,然后传送至所有已订阅此主题的或送消费者。

主题目标也支持长期订阅。长期订阅表示消费者已注册了主题目标,但在消息到达目标时改消费者可以处于非活动状态。当消费者再次处于活动状态时,将会接收该消息。如果消费者均没有注册某个主题目标,该主题只保留注册了长期订阅的非活动消费者的消息。与PTP消息传递模型不同,pub/sub消息传递模型允许多个主题订阅者接收同一条消息。JMS一直保留消息,直至所有主题订阅者都接收到消息为止。pub/sub消息传递模型基本上时一个推模型。在该模型中,消息会自动广播,消费者无须通过主动请求或轮询主题的方法来获得新的消息。

上面两种消息传递模型里,我们都需要定义消息生产者和消费者,生产者吧消息发送到JMS Provider的某个目标地址(Destination),消息从该目标地址传送至消费者。消费者可以同步或异步接收消息,一般而言,异步消息消费者的执行和伸缩性都优于同步消息接收者。

使用同步方式接收消息的话,消息订阅者调用receive()方法。在receive()中,消息未到达或在到达指定时间之前,方法会阻塞,直到消息可用。
  使用异步方式接收消息的话,消息订阅者需注册一个消息监听者,类似于事件监听器,只要消息到达,JMS服务提供者会通过调用监听器的onMessage()递送消息。

JMS接口

JMS应用程序由如下基本模块组成:
1.管理对象(Administered objects)-连接工厂(Connection Factories)和目的地(Destination)
2.连接对象(Connections)
3.会话(Sessions)
4.消息生产者(Message Producers)
5.消息消费者(Message Consumers)
6.消息监听者(Message Listeners)

jms.png
  • JMS管理对象
    管理对象(Administered objects)是预先配置的JMS对象,由系统管理员为使用JMS的客户端创建,主要有两个被管理的对象:

  • 连接工厂(ConnectionFactory)和目的地(Destination)
    这两个管理对象由JMS系统管理员通过使用Application Server管理控制台创建,存储在应用程序服务器的JNDI名字空间或JNDI注册表。
    客户端使用一个连接工厂对象连接到JMS服务提供者,它创建了JMS服务提供者和客户端之间的连接。JMS客户端(如发送者或接受者)会在JNDI名字空间中搜索并获取该连接。使用该连接,客户端能够与目的地通讯,往队列或话题发送/接收消息。让我们用一个例子来理解如何发送消息:

QueueConnectionFactory queueConnFactory = (QueueConnectionFactory) initialCtx.lookup ("primaryQCF");
Queue purchaseQueue = (Queue) initialCtx.lookup ("Purchase_Queue");
Queue returnQueue = (Queue) initialCtx.lookup ("Return_Queue");

目的地指明消息被发送的目的地以及客户端接收消息的来源。JMS使用两种目的地,队列和话题。如下代码指定了一个队列和话题。
创建一个队列Session

QueueSession ses = con.createQueueSession (false, Session.AUTO_ACKNOWLEDGE);  //get the Queue object  
Queue t = (Queue) ctx.lookup ("myQueue");  //create QueueReceiver  
QueueReceiver receiver = ses.createReceiver(t); 

创建一个话题Session

TopicSession ses = con.createTopicSession (false, Session.AUTO_ACKNOWLEDGE); // get the Topic object  
Topic t = (Topic) ctx.lookup ("myTopic");  //create TopicSubscriber  
TopicSubscriber receiver = ses.createSubscriber(t);  
  • JMS连接
    连接对象封装了与JMS提供者之间的虚拟连接,如果我们有一个ConnectionFactory对象,可以使用它来创建一个连接。
Connection connection = connectionFactory.createConnection();
创建完连接后,需要在程序使用结束后关闭它:
connection.close();
  • JMS 会话(Session)
    Session是一个单线程上下文,用于生产和消费消息,可以创建出消息生产者和消息消费者。
    Session对象实现了Session接口,在创建完连接后,我们可以使用它创建Session。
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
  • JMS消息生产者
    消息生产者由Session创建,用于往目的地发送消息。生产者实现MessageProducer接口,我们可以为目的地、队列或话题创建生产者;
MessageProducer producer = session.createProducer(dest);
MessageProducer producer = session.createProducer(queue);
MessageProducer producer = session.createProducer(topic);
创建完消息生产者后,可以使用send方法发送消息:
producer.send(message);
  • JMS消息消费者
    消息消费者由Session创建,用于接受目的地发送的消息。消费者实现MessageConsumer接口,,我们可以为目的地、队列或话题创建消费者;
MessageConsumer consumer = session.createConsumer(dest);
MessageConsumer consumer = session.createConsumer(queue);
MessageConsumer consumer = session.createConsumer(topic);
  • JMS消息监听器
    JMS消息监听器是消息的默认事件处理者,他实现了MessageListener接口,该接口包含一个onMessage方法,在该方法中需要定义消息达到后的具体动作。通过调用setMessageListener方法我们给指定消费者定义了消息监听器
Listener myListener = new Listener();
consumer.setMessageListener(myListener);

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 124,445评论 18 136
  • 什么是Java消息服务 Java消息服务指的是两个应用程序之间进行异步通信的API,它为标准消息协议和消息服务提供...
    雨帶著眼淚滑落阅读 730评论 1 4
  • 一、 消息队列概述 消息队列中间件是分布式系统中重要的组件,主要解决应用耦合、异步消息、流量削锋等问题。实现高性能...
    步积阅读 49,161评论 10 138
  • 1、前言 之前我们通过两篇文章(架构设计:系统间通信(19)——MQ:消息协议(上)、架构设计:系统间通信(20)...
    境里婆娑阅读 1,489评论 0 4
  • 1 消息队列概述 消息队列中间件是分布式系统中重要的组件,主要解决应用耦合,异步消息,流量削锋等问题。实现高性能,...
    Bobby0322阅读 9,431评论 0 24
  • 什么 蓝瘦香菇 我伙呆 你妹 什么 绿茶婊 国籍婊 我靠 你们通通 被妖风刮跑 你们通通 被怪兽吃掉 我的 汉语时...
    向日葵爱呀爱太阳阅读 82评论 0 0
  • 作者:林清玄 二十多年前的乡下没有路灯,夜里穿过田野要回到家里,差不多是摸黑的,平常时日,都是借着微明的天光,摸索...
    揉皱的蔓越莓阅读 103评论 0 2
  • 魏小明 个人简介: 中国著名雕塑家 画家 清华大学美术学院教授 博士生导师 北京美术家协会副主席 1957年出生于...
    665d367f6f16阅读 676评论 0 0
  • 在黑夜里,拥它入怀,冰冷坚硬。 接收了理智的最大值。 像猫一样溜在城市的角落, 天气开始淡出我的视线 昨夜是月朗星...
    树下的老石头阅读 284评论 0 2