基础概念
JMS(Java Message Service) Java消息服务,是应用之间通信的一套API,是一个面向消息中间件的API.他为标准消息协议和消息服务提供了一组通用接口.包括创建,发送,读取信息等等.
在J2EE中,应用之间使用JMS通信时,他们之间并不是直接相连,而是通过一个共同的消息收发服务相连,从而实现解耦.
应用场景
聊天室:基于事件触发,向所有链接服务器的客户端发送消息.这个时候消息接受者不需要在线.服务器发送了消息就不用在管了.等客户端上线的时候能保证收到消息.
企业应用之间的通信:当A应用触发事件时,B,C等N个节点想从A那里获取消息
优势
1) 可移植性: JMS规范包括两种消息模式:点对点和发布者/订阅者.由于多个生产商的支持并且由规范和Java平台支撑,可以轻易实现面向消息的操作,并具有在不同的消息中间件的可移植性.
2) 支持同步/异步
3) 事件驱动
4) 消息可靠:消息只会传递一次,避免重复创建消息
JMS元素
1.JMS规范:
JMS定义了Java 中访问消息中间件的接口,并没有给予实现,实现JMS接口的消息中间件成为JMS Provider,例如:Active MQ
2.JMS Provider
实现JMS接口和规范的消息中间件
3JMS message:
JMS的消息,JMS消息由三部分组成:
消息头、
消息属性、
消息体
A.消息头包含消息的识别消息和路由消息,消息头包含一些标准的属性如下:
(1)
JMSDestination: 消息发送的目的地,主要是指Queue和Topic,
由send方法设置.
(2)
JMSDeliveryMode:传送模式。有两种:
持久模式和
非持久模式。(1)
一条持久性的消息应该被传输"一次仅仅一次",这就意味着如果JMS提供者出现故障,该消息并不会丢失,它会在服务器恢复之后再次传递。(2)
一条非持久的消息最多会传递一次,这意味着服务器出现故障,该消息将永远丢失。
由send方法设置.
(3)
JMSExpiration:消息过期时间,等于Destination的send方法中的timeToLive值加上发送时刻的GMT的时间值。
如果timeToLive值等于零,则JMSExpiration被设置为零,表示该消息永不过期。
如果发送后,在消息过期时间之后消息还没有被发送到目的地,则该消息被清除。
由send方法设置
(4)
JMSPriority:消息优先级,从0-9十个级别,0-4是普通消息,5-9是加急消息。JMS不要求JMS Provider严格按照这十个优先级发送消息,但必须保证加急消息要先于普通消息到达,默认是4级。
由send方法设置
(5)
JMSMessageID:唯一识别每个消息的标识,由JMS Provider产生。
由send方法设置
(6)
JMSTimestamp:一个JMS Provider在调用send()方法时自动设置,它是消息被发送和消费者实际接收的时间差。
由客户端设置
(7)
JMSCorrelationID:用来连接到另外一个消息,典型的应用是在回复消息中连接到原消息。在大多数情况下,JMSCorrelationID用于将一条消息标记为对JMSMessageID标示的上一条消息的应答,不过,JMSCorrelationID可以是任何值,不仅仅是JMSMessageID。由客户端设置
(8)
JMSType: 消息类型的标识符,
由客户端设置
(9)
JMSReplyTo: 提供本消息回复消息的目的地址,
由客户端设置
(10)
JMSRedelivered:如果一个客户端收到一个设置了JMSRedelivered属性的消息,则表示可能客户端曾经在早些时候收到过该消息,但并没有签收(acknowledged)。
如果该消息被重新传送,JMSRedelivered=true
否则 JMSRedelivered=flase 。由JMS Provider设置
B.消息体,JMS API定义了5种消息体格式,也叫消息类型,可以使用不同形式发送接收数据,并可以兼容现有的消息格式。包括:TextMessage、MapMessage、BytesMessage、StreamMessage、ObjectMessage
Text message : javax.jms.TextMessage,表示一个文本对象。Object message : javax.jms.ObjectMessage,表示一个JAVA对象。Bytes message : javax.jms.BytesMessage,表示字节数据。Stream message :javax.jms.StreamMessage,表示java原始值数据流。Map message : javax.jms.MapMessage,表示键值对。
C.
消息属性,包含以下三种类型的属性:
1.应用程序设置和添加的数据,比如:message.setStringProperty("userName",userName);
2.JMS定义的属性,使用"JMSX"作为属性名的前缀, connection.getMetaData().getJMSXPropertyNames() 方法返回所有连接支持的JMSX属性的名字。
3.JMS供应商特定的属性
4.JMS producer
消息生产者,创建和发送JMS消息的客户端应用
5.JMS consumer
消息消费者,创建和处理JMS消息的客户端应用
6.Connection factory:
连接工厂,用来创建连接对象,以连接到JMS的provider
7.JMS Connection:
封装了客户与JMS提供者之间的一个虚拟的连接
8.JMS Session:
是生产和消费消息的一个单线程上下文.会话用于创建消息生产者(producer)、消息消费者(consumer)和消息(message)等。会话提供了一个事务性的上下文,在这个上下文中,一组发送和接收被组合到了一个原子操作中。
9.Destination:
消息发送到的目的地
10.Acknowledge:
签收
11.Transaction:
事务
12.JMS client:
用来收发消息的Java应用
JMS Domains
定义了两种消息传递域:点对点(point-to-point/ptp/p2p);发布/订阅(publish/subscribe pub/sub)
1.点对点
在点对点消息传送模型中,应用程序由消息队列,发送者,接收者组成。每一个消息发送给一个特殊的消息队列,该队列保存了所有发送给它的消息(除了被接收者消费掉的和过期的消息)。点对点消息模型有一些特性,
a.每个消息只能有一个消费者
b.消息的生产者和消费者之间没有时间上的依赖性.消息发送后,无论生产者是否在线,消费者都可以提取消息.
c消费者在接受到消息时,会发出确认通知(acknowledgement)
2.发布/订阅
发布者发布一个消息,该消息通过topic传递给所有的客户端。在这种模型中,发布者和订阅者彼此不知道对方,是匿名的且可以动态发布和订阅topic。topic主要用于保存和传递消息,且会一直保存消息直到消息被传递给客户端。
1.一个消息可以传递给多个订阅者
2.发布者和订阅者有时间依赖性,只有当客户端创建订阅后才能接受消息,且订阅者需一直保持活动状态以接收消息。
3.为了缓和这样严格的时间相关性,JMS允许订阅者创建一个可持久化的订阅。这样,即使订阅者没有被激活(运行),它也能接收到发布者的消息。
接收消息
同步
使用同步方式接收消息的话,消息订阅者调用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)
1.JMS管理对象
管理对象(Administered objects)是预先配置的JMS对象,由系统管理员为使用JMS的客户端创建,主要有两个被管理的对象:
a
连接工厂(ConnectionFactory)
b.
目的地(Destination)
这两个管理对象由JMS系统管理员通过使用Application Server管理控制台创建,存储在应用程序服务器的JNDI名字空间或JNDI注册表。
a.
连接工厂(ConnectionFactory)
客户端使用一个连接工厂对象连接到JMS服务提供者,它创建了JMS服务提供者和客户端之间的连接。JMS客户端(如发送者或接受者)会在JNDI名字空间中搜索并获取该连接。使用该连接,客户端能够与目的地通讯,往队列或话题发送/接收消息。让我们用一个例子来理解如何发送消息:
QueueConnectionFactory queueConnFactory = (QueueConnectionFactory) initialCtx.lookup ("primaryQCF"); Queue purchaseQueue = (Queue) initialCtx.lookup ("Purchase_Queue"); Queue returnQueue = (Queue) initialCtx.lookup ("Return_Queue");
b.目的地(Destination)
目的地指明消息被发送的目的地以及客户端接收消息的来源。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);
2.JMS连接
连接对象封装了与JMS提供者之间的虚拟连接,如果我们有一个ConnectionFactory对象,可以使用它来创建一个连接。
Connection connection = connectionFactory.createConnection();
创建完连接后,需要在程序使用结束后关闭它:
connection.close();
3.JMS 会话(Session)
Session是一个单线程上下文,用于生产和消费消息,可以创建出消息生产者和消息消费者。
Session对象实现了Session接口,在创建完连接后,我们可以使用它创建Session。
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
4.JMS消息生产者
消息生产者由Session创建,用于往目的地发送消息。生产者实现MessageProducer接口,我们可以为目的地、队列或话题创建生产者;
MessageProducer producer = session.createProducer(dest); MessageProducer producer = session.createProducer(queue); MessageProducer producer = session.createProducer(topic);
创建完消息生产者后,可以使用send方法发送消息:
producer.send(message);
5.JMS消息消费者
消息消费者由Session创建,用于接受目的地发送的消息。消费者实现MessageConsumer接口,,我们可以为目的地、队列或话题创建消费者;
MessageConsumer consumer = session.createConsumer(dest); MessageConsumer consumer = session.createConsumer(queue); MessageConsumer consumer = session.createConsumer(topic);
6.JMS消息监听器
JMS消息监听器是消息的默认事件处理者,他实现了MessageListener接口,该接口包含一个onMessage方法,在该方法中需要定义消息达到后的具体动作。通过调用setMessageListener方法我们给指定消费者定义了消息监听器
<wiz_code_mirror>
Listener myListener = new Listener(); consumer.setMessageListener(myListener);
参考内容:
https://howtodoinjava.com/ Java Tutorials List
oracle 官方文档