JMS:Java消息服务(Java Message Service)应用程序接口,是一个Java平台中关于面向消息中间件(MOM)的API,用于在两个应用程序之间或分布式系统中发送消息,进行异步通。
MQ(Message Queue)是消息队列的意思,干嘛用的呢,就是一个消息的接受和转发的容器,可用于消息推送。ActiveMQ 是Apache出品,最流行的,能力强劲的一个开源的消息队列软件。ActiveMQ是一个独立的JMS Provider。
一. JMS基础
1.连接工厂(JMS connectionFactory)
连接工厂是客户用来创建连接的对象。根据JNDI来查询。
2.连接(connection)
JMS Connection封装了客户与JMS提供者之间的一个虚拟的连接。
3.会话(session)
JMS Session是生产消息和消费消息的一个单线程上下文。会话用于创建消息生产者(producer)、消息消费者(consumer)和消息(message)等。会话提供了一个事务性的上下文,在这个上下文中,一组发送和接收被组合到了一个原子操作中。
4.目的地(destination)
目的地是客户用来指定它生产的消息的目标和它消费的消息的来源的对象。
消息传递域:1. Point-to-Point 消息(P2P) 点对点;
2. Publish Subscribe messaging(Pub/Sub)发布/订阅消息
在点对点消息传递域中,目的地被称为队列(queue);在发布/订阅消息传递域中,目的地被称为主题(topic)。
这两种消息传递模型非常相似,但有以下区别:
P2P消息传递模型规定了一条消息之恩能够传递费一个接收方;
Pub/sub消息传递模型允许一条消息传递给多个接收方。
每个模型都通过扩展公用基类来实现。例如:javax.jms.Queue和Javax.jms.Topic都扩展自javax.jms.Destination类。
5.1消息生产者(producer)
消息生产者是会话创建的一个对象,用于把消息发送到一个目的地。
5.2消息消费者(consumer)
消息消费者是由会话创建的一个对象,它用于接收发送到目的地的消息。
同步消费:通过调用消费者的receive方法从目的地中显式提取消息。receive方法可以一直阻塞到消息到达。
异步消费:客户可以为消费者注册一个消息监听器,以定义在消息到达时所采取的动作。消费者类必须实现MessageListener接口,然后在onMessage方法中监听消息的到达并处理。
6.消息(message)
JMS消息由以下三部分组成:
6.1.消息头(head):每条JMS 消息都必须具有消息头。头字段包含用于路由和识别消息的值。可以通过多种方式来设置消息头的值(getter和setter方法):
a. 由JMS 提供者在生成或传送消息的过程中自动设置;
b. 由生产者客户机通过在创建消息生产者时指定的设置进行设置;
c. 由生产者客户机逐一对各条消息进行设置。
6.2.消息属性(property):消息可以包含称作属性的可选头字段,它们是以属性名和属性值对的形式制定的。可以将属性是为消息头得扩展,其中可以包括如下信息:
创建数据的进程;
数据的创建时间;
每条数据的结构。
JMS提供者也可以添加影响消息处理的属性,如是否应压缩消息或如何在消息生命周期结束时废弃消息。
6.3.消息体:包含要发送给接收应用程序的内容。每个消息接口特定于它所支持的内容类型。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 Provider (ActiveMQ)
ActiveMQ官方网站下载:http://activemq.apache.org/,这里我下载的是apache-activemq-5.11.1-bin.tar。
下载并解压缩后,双击文件里\bin\macosx\wrapper即可启动ActiveMQ,再登陆:http://localhost:8161/admin/,(可能会需要登陆验证,初始的账号和密码都是admin)创建一个Queue,命名为FirstQueue。
三. 创建项目并运行
在Idea中创建项目,并分别创建Sender.java和Receiver.java。
3.1 Sender.java
package com.sankuai.xm.eas.mbp.services;
/**
* Created by Endstart on 15/3/3.
*/
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.DeliveryMode;
import javax.jms.Destination;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
public class Sender {
private static final int SEND_NUMBER = 5;
public static void main(String[] args) {
// ConnectionFactory :连接工厂,JMS 用它创建连接
ConnectionFactory connectionFactory;
// Connection :JMS 客户端到JMS Provider 的连接
Connection connection = null;
// Session: 一个发送或接收消息的线程
Session session;
// Destination :消息的目的地;消息发送给谁.
Destination destination;
// MessageProducer:消息发送者
MessageProducer producer;
// TextMessage message;
// 构造ConnectionFactory实例对象,此处采用ActiveMq的实现jar
connectionFactory = new ActiveMQConnectionFactory(
ActiveMQConnection.DEFAULT_USER,
ActiveMQConnection.DEFAULT_PASSWORD,
"tcp://localhost:61616");
try {
// 构造从工厂得到连接对象
connection = connectionFactory.createConnection();
// 启动
connection.start();
// 获取操作连接
session = connection.createSession(Boolean.TRUE,
Session.AUTO_ACKNOWLEDGE);
// 获取session注意参数值xingbo.xu-queue是一个服务器的queue,须在在ActiveMq的console配置
destination = session.createQueue("FirstQueue");
// 得到消息生成者【发送者】
producer = session.createProducer(destination);
// 设置不持久化,此处学习,实际根据项目决定
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
// 构造消息,此处写死,项目就是参数,或者方法获取
sendMessage(session, producer);
session.commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (null != connection)
connection.close();
} catch (Throwable ignore) {
}
}
}
public static void sendMessage(Session session, MessageProducer producer)
throws Exception {
for (int i = 1,j=i; i < 5+j; i++) {
TextMessage message = session
.createTextMessage("ActiveMq 发送的消息" + i);
// 发送消息到目的地方
System.out.println("发送消息:" + "ActiveMq 发送的消息" + i);
producer.send(message);
}
}
}
3.2 Receiver.java
package com.sankuai.xm.eas.mbp.services;
/**
* Created by Endstart on 15/3/3.
*/
import javax.jms.*;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Receiver {
// private Logger log = LoggerFactory.getLogger(Receiver.class);
public static void main(String[] args) {
final Logger log = LoggerFactory.getLogger(Receiver.class);
// ConnectionFactory :连接工厂,JMS 用它创建连接
ConnectionFactory connectionFactory;
// Connection :JMS 客户端到JMS Provider 的连接
Connection connection = null;
// Session: 一个发送或接收消息的线程
Session session;
// Destination :消息的目的地;消息发送给谁.
Destination destination;
// 消费者,消息接收者
MessageConsumer consumer;
connectionFactory = new ActiveMQConnectionFactory(
ActiveMQConnection.DEFAULT_USER,
ActiveMQConnection.DEFAULT_PASSWORD,
"tcp://localhost:61616");
try {
// 构造从工厂得到连接对象
connection = connectionFactory.createConnection();
// 启动
connection.start();
// 获取操作连接
session = connection.createSession(Boolean.FALSE,
Session.AUTO_ACKNOWLEDGE);
// 获取session注意参数值xingbo.xu-queue是一个服务器的queue,须在在ActiveMq的console配置
destination = session.createQueue("FirstQueue");
consumer = session.createConsumer(destination);
// 缺少监听器
// consumer.setMessageListener(new MessageListener() {
// @Override
// public void onMessage(Message message) {
// String receivedMessage = null;
// try {
// if (message != null && message instanceof TextMessage) {
// receivedMessage = ((TextMessage) message).getText();
// } else {
// log.warn("无法识别的消息类型:" + message.getClass().getSimpleName());
// return;
// }
// // processReceivedMessage(receivedMessage);
// } catch (Exception e) {
// log.error("处理消息失败 msg=" + receivedMessage, e);
// }
// }
// });
while (true) {
//设置接收者接收消息的时间,为了便于测试,这里谁定为100s
TextMessage message = (TextMessage) consumer.receive(500000);
if (null != message) {
System.out.println("收到消息:" + message.getText());
} else {
break;
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (null != connection)
connection.close();
} catch (Throwable ignore) {
}
}
}
}
3.3 运行
运行Sender.java
IDEA结果:
ActiveMQ里结果:
再运行Receiver.java
IDEA结果: