一、安装和启动
官网:http://activemq.apache.org/
1、安装启动
方式一:
$ tar -zxvf apache-activemq-5.11.1-bin.tar.gz
$ mv apache-activemq-5.11.1 activemq
如果启动脚本 activemq 没有可执行权限,此时则需要授权(此步可选)
$ cd /activemq-01/bin/
$ chmod 755 ./activemq
$ ./activemq start/stop/status
方式二(Windows):
下载之后解压出来,目录如下
打开bin目录下的地址可以看到有两个文件夹win32和win64,可以根据自己的电脑情况来选择。
我这里选择win64位的,点击activemq.bat进行启动,如图所示就是启动结束了。启动服务(保持黑窗口开启)
那么接下来我们在浏览器中输入 http://localhost:8161/admin 地址,弹出输入用户名密码的页面,默认用户名密码都为admin
2、ActiveMQ 需要用到两个端口
一个是消息通讯的端口(默认为 61616)
一个是管理控制台端口(默认为 8161)可在conf/jetty.xml 中修改
<bean id="jettyPort" class="org.apache.activemq.web.WebConsolePort" init-method="start">
<!-- the default port number for the web console -->
<property name="host" value="0.0.0.0"/>
<property name="port" value="8161"/>
</bean>
3、检查是否启动
ActiveMQ默认采用61616端口提供JMS服务,使用8161端口提供管理控制台服务,执行以下命令检验是否成功启动ActiveMQ
1.查看端口是否打开:netstat -an | grep 61616
2.查看控制台输入或者日志文件
3.访问ActiveMQ的管理页面:http://ip:8161/admin/
默认的用户名和密码是admin/admin
4、安全配置(消息安全)
ActiveMQ 如果不加入安全机制的话,任何人只要知道消息服务的具体地址
(包括 ip,端口,消息地址[ 队列或者主题地址] ) ,都可以肆无忌惮的发送、接收消息。
关于 ActiveMQ 安装配置http://activemq.apache.org/security.html
二、管理界面
进入管理界面的地址:http://localhost:8161(IP:端口号)
1、Queues(队列)
标示 | 描述 |
---|---|
Name | 队列名称 |
Number Of Pending Messages | 队列中有多少个消息等待出队列 |
Number Of Consumers | 队列中有多少个消费者 |
Messages Enqueued | 队列共有多少个信息 |
Messages Dequeued | 队列中已经出列多少个消息 |
2、Topics(主题模式)
这里只有 Name、Number Of Consumers、Messages Enqueued、Messages Dequeued
三、ActiveMQ常用类、方法
1、连接对象(Connection)
Connection【javax.jms.Connection】
方法 | 返回值 | 描述 |
start() | void | 启动连接 |
---|---|---|
createSession(boolean var1, int var2) | Session | 使用连接对象创建会话(session)对象 |
// 创建连接工厂
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory();
// 设置服务地址
activeMQConnectionFactory.setBrokerURL(ACTIVEMQ_URL);
// 打开连接
connection.start();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
2、通道对象(Session)
Session【javax.jms.Session】
方法 | 返回 | 描述 |
createQueue(String var1) | Queue | 创建queue模式 |
createTopic(String var1) | Topic | 创建Topic模式 |
createProducer(Destination var1) | MessageProducer | 创建生产者 |
createConsumer(Destination var1) | MessageConsumer | 创建消费者 |
commit() | void | |
rollback() | void |
消息类型(Message)
JAVA消息服务定义了6种JMS提供者必须支持的 Message 接口类型。尽管JMS定义了Message接口,但它并未定义它们的实现方式。这就允许提供者以它们自己的方式实现和传送消息,同时为JMS应用程序开发者维护了一个兼容的标准接口。这6个消息接口是Message和它的5个子接口:TextMessage、StreamMessage、MapMessage、ObjectMessage 和 ByteMessage。
方法 | 返回 | 描述 |
createMessage() | Message | 创建消息对象 |
createTextMessage() | TextMessage | 创建文本消息对象 |
createTextMessage(String var1) | TextMessage | 创建文本消息对象 |
createObjectMessage() | ObjectMessage | 创建对象消息对象 |
createObjectMessage(Serializable var1) | ObjectMessage | 创建对象消息对象 |
createMapMessage() | MapMessage | 创建映射消息对象 |
createBytesMessage() | BytesMessage | 创建字节流消息对象 |
createStreamMessage() | StreamMessage | 创建流消息对象 |
3.1 Message
最简单的消息类型是javax.jms.Message,它担当了其他消息类型基接口(base interface)的角色。可按一下方式创建Message类型,并将它用作一条不含有效负载的JMS消息:
//使用者发布者创建并发送消息
Message message = pubSession .createTextMessage();
publisher.publish(message );
//接受消息
@Override
public void onMessage(Message message) {
这种类型的消息仅仅包含了JMS消息头和消息属性,而且,它仅限用于事件通知,它仅用于事件通知。一个事件通知就是出现某些情况的一个广播、告警或者通知。如果业务场景需要一个不含有效负载的简单通知,轻量级消息类型就是实现它的最有效方式。
例如为了广播通知某个特定类中的一个异常,你可以发布一条不含有效负载的异常文本消息,如下所示:
//发送异常
...
try{
...
}catch(Exception up){
Message message = Sesstion.createMessage();
message.setStringProperty("Exception",up.getMessage());
publisher.publish(message);
throw up;
}
//接受异常
...
public void onMessage(Message message){
...
System.out.println("Exception:"+message.getStringProperty());
...
}
...
3.2 TextMessage
文本消息可以使用Session接口中定义的两个工厂方法之一来创建。其中一个工厂方法没有使用参数,就会产生出不含有效负载的TextMessage对象。另一个工厂方法则使用一个string类型的有效负载作为参数,生产出“准备就绪可传送”的TextMessage对象
TextMessage textMessage = Session.createTextMessage();
textMessage.setText("Hello World!");
topicPublisher.publish(textMessage);
...
TextMessage textMessage = session.createTextMessage("Hello!");
queueSender.send(textMessage);
3.3 ObjectMessage
对象消息可以使用Session接口中的两个工厂方法中的一个来创建
//订单一个可序列化对象
Order order = new Order();
...
ObjectMessage objectMessage = Session.createObjectMessage();
objectMessage.setObject(order);
queueSender.send(objectMessage);
...
ObjectMessage objectMessage = Session.createObjectMessage(order);
topicPublisher.publish(objectMessage);
在消费者接受objectMessage时,它可以使用getObject()方法提取出有效负载。如果传送的ObjectMessage不含有效负载,getObject()方法将返回一个null值。
public void onMessage(Message message){
try{
ObjectMessage objectMessage =(ObjectMessage)message;
Order order =(Order)objectMessage.getObject();
...
}catch(JMSException jmse){
...
}
注意:使用ObjectMessages时,消息生产者和消费者二者都必须是JMS兼容的。
3.4 BytesMessage
这种类型懈怠了一组原始类型字节流作为有效负载。
它可以使用应用程序的本机格式来交换数据,这种格式可能不兼容其他现有的Message类型。当JMS纯粹用于两个系统之间的消息传送时,也可以使用这种类型,而且该消息的有效负载对JMS客户端来说是透明的。
如果你使用java.io.DataInputStream和java.io.DataOutputStream,那么以这些I/O类为基础的ByteMessage接口方法,就会让你觉得熟悉。
BytesMessage bytesMessage = Session.createBytesMessage();
bytesMessage.writeChar('R');
byteMessage.writeInt(10);
byteMessage.writeUTF("Hello");
消息响应
public void onMessage(Message message){
try{
BytesMessage byteMessage =(BytesMessage)message;
char c = byteMessage.readChar();
int i = byteMessage.readInt();
String s = byteMessage.readUTF();
}catch(JMSException jmse){
....
}
}
ByteMessage是可移植性最好的而一种消息类型,因此他在于非JMS消息类型传送客户端通信时非常有用。有些情况下,一个JMS客户端可以是一类路由器,它消费来自某个消息源的消息,并将他们传送给一个目的地。路由选择应用程序可能不需要知道它们传输的数据内容,并因此可以选择使用ByteMessage将有效负载作为二进制数据,从一个位置传送到其他位置。
3.5 MapMessage
这种类型携带了一组键/值对作为有效负载。有效负载类似与一个Java.util.Properties对象,除了有效负载值必须是Java原始数据类型和Strings型之外。
本质上,MapMessage的工作方式类似于JMS属性:任何键/值对都可以写入有效负载。其中名称必须是一个String对象,而值则可以是String类型或原始数据类型。
MapMessage mapMessage =Session.createMapMessage();
mapMessage.setInt("Age",88);
mapMessage.setFloat("Weight",234);
mapMessage.setString("Name","Smith");
mapMessage.setObject("Height",new Double(150.32));
...
int age = mapMessage.getInt("Age");
float weight = mapMessage.getFloat("Weight");
String name = mapMessage.getString("Name");\
Double height = (Double)mapmessage.getObject("Height");
3.6 StreamMessage
StreamMesage携带了一个Java原始数据类型流作为有效负载。它提供了一套将格式化字节流映射为Java原始数据类型的简便方法。
StreamMessage保持了写入流时的顺序和原始数据类型,因此它适用于形式转换规则。
四、消息确认机制ACK
消息消费者有没有接收到消息,需要有一种机制让消息提供者知道,这个机制就是消息确认机制。
ACK(Acknowledgement)即确认字符,在数据通信中,接收站发给发送站的一种传输类控制字符。表示发来的数据已确认接收无误。
1、ACK_MODE有几类
我们在开发JMS应用程序的时候,会经常使用到上述ACK_MODE,其中"INDIVIDUAL_ACKNOWLEDGE "只有ActiveMQ支持,当然开发者也可以使用它. ACK_MODE描述了Consumer与broker确认消息的方式(时机),比如当消息被Consumer接收之后,Consumer将在何时确认消息。对于broker而言,只有接收到ACK指令,才会认为消息被正确的接收或者处理成功了,通过ACK,可以在consumer与Broker之间建立一种简单的“担保”机制.
JMS API中约定了Client端可以使用四种ACK_MODE,在javax.jms.Session接口中:
AUTO_ACKNOWLEDGE = 1 自动确认
CLIENT_ACKNOWLEDGE = 2 客户端手动确认
DUPS_OK_ACKNOWLEDGE = 3 自动批量确认
SESSION_TRANSACTED = 0 事务提交并确认
此外AcitveMQ补充了一个自定义的ACK_MODE:
INDIVIDUAL_ACKNOWLEDGE = 4 单条消息确认
2、ACK_TYPE有几类
Client端指定了ACK_MODE,但是在Client与broker在交换ACK指令的时候,还需要告知ACK_TYPE,ACK_TYPE表示此确认指令的类型,不同的ACK_TYPE将传递着消息的状态,broker可以根据不同的ACK_TYPE对消息进行不同的操作。
比如Consumer消费消息时出现异常,就需要向broker发送ACK指令,ACK_TYPE为"REDELIVERED_ACK_TYPE",那么broker就会重新发送此消息。在JMS API中并没有定义ACT_TYPE,因为它通常是一种内部机制,并不会面向开发者。ActiveMQ中定义了如下几种ACK_TYPE(参看MessageAck类):
- DELIVERED_ACK_TYPE = 0 消息"已接收",但尚未处理结束
- STANDARD_ACK_TYPE = 2 "标准"类型,通常表示为消息"处理成功",broker端可以删除消息了
- POSION_ACK_TYPE = 1 消息"错误",通常表示"抛弃"此消息,比如消息重发多次后,都无法正确处理时,消息将会被删除或者DLQ(死信队列)
- REDELIVERED_ACK_TYPE = 3 消息需"重发",比如consumer处理消息时抛出了异常,broker稍后会重新发送此消息
- INDIVIDUAL_ACK_TYPE = 4 表示只确认"单条消息",无论在任何ACK_MODE下
- UNMATCHED_ACK_TYPE = 5 BROKER间转发消息时,接收端"拒绝"消息,在Topic中,如果一条消息在转发给“订阅者”时,发现此消息不符合Selector过滤条件,那么此消息将 不会转发给订阅者,消息将会被存储引擎删除(相当于在Broker上确认了消息)
到目前为止,我们已经清楚了大概的原理: Client端在不同的ACK_MODE时,将意味着在不同的时机发送ACK指令,每个ACK Command中会包含ACK_TYPE,那么broker端就可以根据ACK_TYPE来决定此消息的后续操作.