JMS 是 Java Message Service 的简称,即 Java 消息服务。什么是消息服务呢,咱们来看一下 Oracle 官方的定义:java
The Java Message Service (JMS) API is a messaging standard that allows application components based on the Java Platform Enterprise Edition (Java EE) to create, send, receive, and read messages. It enables distributed communication that is loosely coupled, reliable, and asynchronous. 翻译过来就是说,JMS 是一个消息标准,这种标准容许基于 JavaEE 的应用组件能够建立,发送,接受及读取消息。经过 JMS 能够实现松耦合,可依赖及异步的分布式通讯。那么在这一段话中咱们应该注意两点,即首先这是一个标准,相似于 Servlet 标准,并非一个具体的实现。其次,这是一种分布式的通讯机制,而且是异步的。
JMS 只定义了 Java 中访问消息中间件的接口,并无给予实现,实现 JMS 接口的消息中间件称为 JMS Provider。如 Apache 的 ActiveMQ、以及阿里巴巴的 RocketMQ。编程
在 Jave 中,若是两个应用程序之间对各自都不了解,甚至这两个程序可能部署在不一样的大洲上,那么它们之间如何发送消息呢?服务器
当前,CORBA、DCOM、RMI 等 RPC 中间件技术已普遍应用于各个领域。可是面对规模和复杂度都愈来愈高的分布式系统,这些技术也显示出其 局限性:网络
面向消息的中间件(Message Oriented Middleware,MoM)较好的解决了以上问题。发送者将消息发送给消息服务器,消息服务器将消息存放在若干队列中,在合适的时候再将消息转发给接收者。session
面向消息的中间件的优势:数据结构
举个例子,一个应用程序 A 部署在印度,另外一个应用程序部署在美国,而后每当 A 触发某件过后,B 想从 A 获取一些更新信息。固然,也有可能不止一个 B 对 A 的更新信息感兴趣,可能会有 N 个相似 B 的应用程序想从 A 中获取更新的信息。在这种状况下,Jave 提供了最佳的解决方案 JMS,完美解决了上面讨论的问题。app
JMS 一样适用于基于事件的应用程序,如聊天服务,它须要一种发布事件机制向全部与服务器链接的客户端发送消息。JMS 与 RMI 不一样,发送消息的时候,接收者不须要在线。服务器发送了消息,而后就无论了;等到客户端上线的时候,能保证接收到服务器发送的消息。这是一个很强大的解决方案,能处理当今世界不少广泛问题。异步
异步:JMS 天生就是异步的,客户端获取消息的时候,不须要主动发送请求,消息会自动发送给可用的客户端。async
可靠:JMS 保证消息只会递送一次。你们都遇到太重复建立消息问题,而 JMS 能帮你避免该问题,只是避免而不是杜绝,因此在一些糟糕的环境下仍是有可能会出现重复。分布式
消息中间件(JMS Provider):指提供了对 JMS 协议的第三方组件,好比 ActiveMQ 就是一个消息中间件,另外比较知名的还有 KFA, Rabbit MQ 等;
消息模式:分为点对点(Point-to-Point,即P2P)和发布/订阅(Pub/Sub),对应的数据结构分别是队列(Queue)和主题(Topic);
消息(Message): 通讯内容的载体,其结构主要分为消息头,属性和消息体,而且根据存储结构的不一样分为好几种,后面会详细提到;
消息生产者(Provider):产生消息的一方,在 P2P 模式下,指消息发送者(Sender),在 P/S 模式下指消息发布者(Publisher);
消息消费者(Consumer):接收消息的一方,对应于两种模式分别是消息接收者(Receiver)和消息订阅者(Subscriber);
涉及到的概念:
每一个消息都被发送到一个特定的队列,接收者从队列中获取消息。队列保留着消息,直到他们被消费或超时。
P2P 的特色:
总结:若是你但愿发送的每一个消息都应该被成功处理的话,那么你须要 P2P 模式。
涉及到的概念:
客户端将消息发送到主题。多个发布者将消息发送到 Topic,系统将这些消息传递给多个订阅者。
Pub/Sub 的特色:
总结:若是你但愿发送的消息能够不被作任何处理、或者被一个消息者处理、或者能够被多个消费者处理的话,那么能够采用 Pub/Sub 模型
在 JMS 中,消息的产生和消费是异步的。对于消费来讲,JMS 的消费者能够经过两种方式来消费消息。
同步:订阅者或接收者调用 receive 方法来接收消息,receive 方法在可以接收到消息以前(或超时以前)将一直阻塞。
consumer = session.createConsumer(destination); Message message = consumer.receive();
异步:订阅者或接收者能够注册为一个消息监听器。当消息到达以后,系统自动调用监听器的 onMessage 方法。
consumer.setMessageListener(new MessageListener(){ @Override public void onMessage(Message message) { TextMessage textMessage = (TextMessage)message; try { String value = textMessage.getText(); System.out.println("value: "+value); } catch (JMSException e) { // TODO Auto-generated catch block e.printStackTrace(); } } });
在 JMS 的标准协议里,有几个重要的接口,先简单罗列以下:
ConnectionFactory(链接工厂):建立 Connection 的工厂,经过这个对象来建立一个到某个消息服务的链接。
用户用来建立到JMs提供者的链接的被管对象。JMS 客户经过可移植的接口访问链接,这样当下层的实现改变时,代码不须要进行修改。管理员在 JNDI 名字空间中配置链接工厂,这样,JMS 客户才可以查找到它们。根据消息类型的不一样,用户将使用队列链接工厂,或者主题链接工厂。
Connection(链接) :一个具体的链接,由 ConnectionFactory 建立。
链接表明了应用程序和消息服务器之间的通讯链路。在得到了链接工厂后,就能够建立一个与 JMS 提供者的链接。根据不一样的链接类型,链接容许用户建立会话,以发送和接收队列和主题到目标。
Destination(目标) :消息存储的位置,发送者把消息发送到指定位置,消费者从指定位置取消息,那么这个指定位置多是一个 topic 也多是一个 queue,由这个来表示。
目标是一个包装了消息目标标识符的被管对象,消息目标是指消息发布和接收的地点,或者是队列,或者是主题。JMS 管理员建立这些对象,而后用户经过 JNDI 发现它们。和链接工厂同样,管理员能够建立两种类型的目标,点对点模型的队列,以及发布者/订阅者模型的主题。
Session(会话) :一个发送或接收消息的线程,由 Connection 建立的用于操做消息的接口,本接口能够直接用来建立消息的生产者对象。
表示一个单线程的上下文,用于发送和接收消息。因为会话是单线程的,因此消息是连续的,就是说消息是按照发送的顺序一个一个接收的。会话的好处是它支持事务。若是用户选择了事务支持,会话上下文将保存一组消息,直到事务被提交才发送这些消息。在提交事务以前,用户可使用回滚操做取消这些消息。一个会话容许用户建立消息生产者来发送消息,建立消息消费者来接收消息。
MessageProducer(消息生产者) :消息的生产者,包括 QueueSender 和 TopicPublisher
由会话建立的对象,用于发送消息到目标。用户能够建立某个目标的发送者,也能够建立一个通用的发送者,在发送消息时指定目标。
MessageConsumer(消息消费者) :消息的消费者, 包括 QueueReceiver 和 TopicSubscriber
会话建立的对象,用于接收发送到目标的消息。消费者能够同步地(阻模式),或异步(非阻寒)接收队列和主题类型的消息。
MessageListener(消息监听器) :提供给消费者监听消息使用的,在添加了某个监听器以后,一旦消费到达,则会调用其 onMessage 方法。
Message接口(消息):是在消费者和生产者之间传送的对象,也就是说从一个应用程序创送到另外一个应用程序。
JMS 客户端使用 JMS 消息与系统通信,JMS 消息虽然格式简单可是很是灵活。一个消息有三个主要部分:
JMS 消息头预约义了若干字段用于客户端与JMS提供者之间识别和发送消息,预编译头以下:
JMSDestination:消息发送的目的地,主要是指 Queue 和 Topic,由 session 建立而由生产者的 send 方法设置。
JMSDeliveryMode:传送模式,有两种即久模式和非持久模式。一条持久性的消息应该被传输"一次仅仅一次",这就意味着若是 JMS 提供者出现故障,该消息并不会丢失,它会在服务器恢复以后再次传递。一条非持久的消息最多会传递一次,这意味着服务器出现故障,该消息将永远丢失。由 session 建立而由消息生产者的 send 方法设置。
JMSMessageID:惟一识别每一个消息的标识,由 JMS 消息生产者产生。由 send 方法设置。
JMSTimestamp:一个 JMS Provider 在调用 send() 方法时自动设置,它是消息被发送和消费者实际接收的时间差。由客户端设置。
JMSCorrelationI`:用来链接到另一个消息,典型的应用是在回复消息中链接到原消息。在大多数状况下,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 方法设置。
一个消息的消息头有这些属性,咱们能够按照须要对这个消息的消息进行设计,在将这个消息使用消息生产者的 send() 方法发送到消息服务上。
咱们能够给消息设置自定义属性,这些属性主要是提供给应用程序的。对于实现消息过滤功能,消息属性很是有用,JMS API 定义了一些标准属性,JMS 服务提供者能够选择性的提供部分标准属性。
在消息体中,JMS API 定义了五种类型的消息格式,让咱们能够以不一样的形式发送和接受消息,并提供了对已有消息格式的兼容。不一样的消息类型以下: