学习资源:https://www.bilibili.com/video/BV164411G7aB?p=3

文章目录

  • ​​MQ的产品学习说明​​
  • ​​MQ的作用定义​​
  • ​​特点​​
  • ​​官网介绍、下载、安装​​
  • ​​控制台访问​​
  • ​​java编码mq标准api讲解​​
  • ​​消息生产者编码​​
  • ​​消息消费者编码​​
  • ​​消息消费者-MessageListener模式​​
  • ​​消费者三大消费情况​​
  • ​​队列案例小总结​​
  • ​​java编码topic讲解​​
  • ​​topic和queue对比​​
  • ​​JMS是什么​​
  • ​​MQ消息中间件的落地产品​​
  • ​​JMS的四大组成元素​​
  • ​​消息的可靠性之queue持久化​​
  • ​​消息的可靠性之topic持久化​​

MQ的产品学习说明

MQ消息中间件–>飞在天上的理念,必然有落地的实现。
目前同系列的MQ产品包括:kafka,rabbitmq,rocketmq,activemq,其他。
以activemq为例,他的技术维度包括:

  • API 接受发送
  • MQ 的高可用
  • MQ 的集群容错配置
  • MQ 的持久化
  • 延时发送
  • 签收机制
  • Spring/SpringBoot 整合

  • 同理可得,其他mq产品,也有类似的技术内容。

用生活中的案例举例子

场景一:学生排队问老师题,一个需要问五分钟,后面的一直等待,效率低。

场景二:按照固定的格式,将问题整理成固定格式发给班长统一收集,然后去干自己的事,老师处理好了会联系。

为什么要使用 MQ ?

解决了耦合调用、异步模型、抵御洪峰流量,保护了主业务,消峰。

系统之间直接调用实际工程落地存在的问题?

1.MQ-activemq学习笔记(上)_java


造成三个严重的问题:

1.系统之间接口耦合严重

1.MQ-activemq学习笔记(上)_消息发送_02


1.MQ-activemq学习笔记(上)_java_03


2.面对大流量并发时,容易被冲垮。

1.MQ-activemq学习笔记(上)_消息发送_04


3.等待同步,存在性能问题

1.MQ-activemq学习笔记(上)_消息发送_05


基于上述三个问题,必须有一种东西,可以达到下面的目标:

1.MQ-activemq学习笔记(上)_java_06


当然,这就是mq了。

MQ的作用定义

1.MQ-activemq学习笔记(上)_java_07


1.MQ-activemq学习笔记(上)_消息发送_08

特点

采用异步模式处理

1.MQ-activemq学习笔记(上)_消息发送_09

1.MQ-activemq学习笔记(上)_消息发送_10

应用系统之间解耦

1.MQ-activemq学习笔记(上)_消息发送_11

官网介绍、下载、安装

官网:http://activemq.apache.org/ 使用java的技术栈,中小型系统activemq够用了,大型的用阿里出品的rocketmq。

怎么玩?

  • 最主要的功能就是实现高可用,高性能,可伸缩,易用,安全的企业级面向消息的系统。
  • 异步消息的消费和处理
  • 控制消息的消费顺序
  • 可以和springboot整合简化代码
  • 配置集群容错的mq集群。

linux下安装

  1. 官网下载
  2. 上传到linux的opt目录下,所有的第三方软件都往这里传。
  3. 解压缩到指定的文件安放位置。比如在根目录下新建myactivemq 文件夹。

解压之后就可以使用bin下面的文件启动了。

解压之后的mq内含的相关文件夹介绍

1.MQ-activemq学习笔记(上)_消息传递_12

常用指令

active需要java环境才可以运行

切换到bin文件夹下之后,执行操作—>

普通启动、关闭、重启: ./activemq start/stop/restart

1.MQ-activemq学习笔记(上)_消息传递_13


activemq的默认端口是61616.

还可以使用ps 命令查看进程是否启动了。

1.MQ-activemq学习笔记(上)_消息发送_14


小技巧:屏蔽grep指令相关的进程

1.MQ-activemq学习笔记(上)_消息传递_15

还可以通过网络查看61616端口是否被监听

netstat -anp |  grep 61616

技巧:启动的时候可以把日志进行追加

1.MQ-activemq学习笔记(上)_java_16

控制台访问

1.MQ-activemq学习笔记(上)_消息传递_17

访问之前先关闭防火墙,或者设置防火墙的访问白名单。这里直接关闭:

1.MQ-activemq学习笔记(上)_java_18

访问一下web管理站点测试一下:

1.MQ-activemq学习笔记(上)_消息传递_19


两个重要的端口

  1. 8161端口提供管理控制台服务
  2. 61616端口提供jms服务

java编码mq标准api讲解

1.新建一个maven工程。

2.导入相关的jar包。

1.MQ-activemq学习笔记(上)_消息发送_20


1.MQ-activemq学习笔记(上)_消息发送_21


3.了解JMS编码整体架构

JMS : Java 消息中间件的服务接口规范,activemq 之上是 mq , 而 mq 之上是JMS 定义的消息规范 。 activemq 是mq 技术的一种理论实现(与之相类似的实现还有 Kafka RabbitMQ RockitMQ ),而 JMS 是更上一级的规范。

1.MQ-activemq学习笔记(上)_java_22

在点对点的消息传递时,目的地称为 队列 queue
在发布订阅消息传递中,目的地称为 主题 topic

1.MQ-activemq学习笔记(上)_java_23

消息生产者编码

public class JmsProduce {
// linux 上部署的activemq 的 IP 地址 + activemq 的端口号
public static final String ACTIVEMQ_URL = "tcp://192.168.17.3:61616";
public static final String QUEUE_NAME = "queue01";

public static void main(String[] args) throws Exception{

// 1 按照给定的url创建连接工程,这个构造器采用默认的用户名密码
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
// 2 通过连接工厂连接 connection 和 启动
javax.jms.Connection connection = activeMQConnectionFactory.createConnection();
// 启动
connection.start();
// 3 创建回话 session
// 两个参数,第一个事务, 第二个签收
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// 4 创建目的地 (两种 : 队列/主题 这里用队列)
Queue queue = session.createQueue(QUEUE_NAME);
// 5 创建消息的生产者
MessageProducer messageProducer = session.createProducer(queue);
// 6 通过messageProducer 生产 3 条 消息发送到消息队列中
for (int i = 1; i < 4 ; i++) {
// 7 创建字消息
TextMessage textMessage = session.createTextMessage("msg--" + i);
// 8 通过messageProducer发布消息
messageProducer.send(textMessage);
}
// 9 关闭资源
messageProducer.close();
session.close();
connection.close();

System.out.println(" **** 消息发送到MQ完成 ****");
}
}

上传消息之后,前往web控制台,控制台说明如下:

1.MQ-activemq学习笔记(上)_消息传递_24

1.MQ-activemq学习笔记(上)_java_25

消息消费者编码

public class JmsConsumer {
public static final String ACTIVEMQ_URL = "tcp://192.168.17.3:61616";
public static final String QUEUE_NAME = "queue01"; // 1对1 的队列

public static void main(String[] args) throws Exception{
// 1 按照给定的url创建连接工程,这个构造器采用默认的用户名密码
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
// 2 通过连接工厂连接 connection 和 启动
javax.jms.Connection connection = activeMQConnectionFactory.createConnection();
// 启动
connection.start();
// 3 创建回话 session
// 两个参数,第一个事务, 第二个签收
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// 4 创建目的地 (两种 : 队列/主题 这里用队列)
Queue queue = session.createQueue(QUEUE_NAME);
// 5 创建消息的消费者
MessageConsumer messageConsumer = session.createConsumer(queue);
while(true){
// 这里是 TextMessage 是因为消息发送者是 TextMessage , 接受处理的
// 也应该是这个类型的消息
TextMessage message = (TextMessage)messageConsumer.receive();
if (null != message){
System.out.println("****消费者的消息:"+message.getText());
}else {
break;
}
}
messageConsumer.close();
session.close();
connection.close();
}
}

web控制台效果:

1.MQ-activemq学习笔记(上)_java_26

recive方法说明

消费者的recive方法是阻塞的,消息队列中为空会一直等。

可以加入等待时间作为参数,过期不候。下为4秒的例子。

1.MQ-activemq学习笔记(上)_java_27


还有一个取不到就离开的api。recive模式是同步阻塞的模式。

消息消费者-MessageListener模式

public class JmsConsumer {
public static final String ACTIVEMQ_URL = "tcp://192.168.17.3:61616";
public static final String QUEUE_NAME = "queue01"; // 1对1 的队列

public static void main(String[] args) throws Exception{
// 1 按照给定的url创建连接工程,这个构造器采用默认的用户名密码
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
// 2 通过连接工厂连接 connection 和 启动
javax.jms.Connection connection = activeMQConnectionFactory.createConnection();
// 启动
connection.start();
// 3 创建回话 session
// 两个参数,第一个事务, 第二个签收
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// 4 创建目的地 (两种 : 队列/主题 这里用队列)
Queue queue = session.createQueue(QUEUE_NAME);
// 5 创建消息的消费者
MessageConsumer messageConsumer = session.createConsumer(queue);
// 通过监听的方式来消费消息
// 通过异步非阻塞的方式消费消息
// 通过messageConsumer 的setMessageListener 注册一个监听器,
// 当有消息发送来时,系统自动调用MessageListener 的 onMessage 方法处理消息
messageConsumer.setMessageListener(new MessageListener() { // 可以用监听器替换之前的同步receive 方法
public void onMessage(Message message) {
if (null != message && message instanceof TextMessage){
TextMessage textMessage = (TextMessage)message;
try {
System.out.println("****消费者的消息:"+textMessage.getText());
}catch (JMSException e) {
e.printStackTrace();
}
}
}
});
// 让主线程不要结束。因为一旦主线程结束了,其他的线程(如此处的监听消息的线程)也都会被迫结束。
// 实际开发中,我们的程序会一直运行,这句代码都会省略。
System.in.read();

messageConsumer.close();
session.close();
connection.close();
}
}

消费者三大消费情况

1.MQ-activemq学习笔记(上)_java_28


情况1:先生产数据,然后只启动消费者1。

结果:消费者1会消费所有的数据。

情况2:一共三条消息,先启动消费者1(可以消耗三条),再启动消费者2。

结果:消费者1消费所有的数据。消费者2不会消费到消息。

情况3:生产者发布6条消息,在此之前已经启动了消费者1和消费者2。

结果:消费者1和消费者2平摊了消息。各自消费3条消息。

疑问:怎么去将消费者1和消费者2不平均分摊呢?而是按照各自的消费能力去消费。我觉得,现在activemq就是这样的机制。

activemq 好像自带负载均衡(轮询思想),当先启动两个队列(Queue)的消费者时,在启动生产者发出消息,此时的消息平均的被两个消费者消费。 并且消费者不会消费已经被消费的消息(即为已经出队的消息)

队列案例小总结

1.MQ-activemq学习笔记(上)_java_29


1.MQ-activemq学习笔记(上)_消息发送_30

1.MQ-activemq学习笔记(上)_消息发送_31

java编码topic讲解

topic介绍

在发布订阅消息传递域中,目的地被称为主题(topic)

发布/订阅消息传递域的特点如下:

(1)生产者将消息发布到topic中,每个消息可以有多个消费者,属于1:N的关系;

(2)生产者和消费者之间有时间上的相关性。订阅某一个主题的消费者只能消费自它订阅之后发布的消息。

(3)生产者生产时,topic不保存消息它是无状态的不落地,假如无人订阅就去生产,那就是一条废消息,所以,一般先启动消费者再启动生产者。

默认情况下如上所述,但是JMS规范允许客户创建持久订阅,这在一定程度上放松了时间上的相关性要求。持久订阅允许消费者消费它在未处于激活状态时发送的消息。一句话,好比我们的微信公众号订阅

1.MQ-activemq学习笔记(上)_消息发送_32

生产者案例

package  com.at.activemq.topic;

import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;

public class JmsProduce_topic {

public static final String ACTIVEMQ_URL = "tcp://192.168.17.3:61616";
public static final String TOPIC_NAME = "topic01";

public static void main(String[] args) throws Exception{
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
Connection connection = activeMQConnectionFactory.createConnection();
connection.start();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

Topic topic = session.createTopic(TOPIC_NAME);

MessageProducer messageProducer = session.createProducer(topic);
for (int i = 1; i < 4 ; i++) {
TextMessage textMessage = session.createTextMessage("topic_name--" + i);
messageProducer.send(textMessage);
MapMessage mapMessage = session.createMapMessage();
}
messageProducer.close();
session.close();
connection.close();
System.out.println(" **** TOPIC_NAME消息发送到MQ完成 ****");
}
}

消费者案例

package  com.at.activemq.topic;

import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;

public class JmsConsummer_topic {
public static final String ACTIVEMQ_URL = "tcp://192.168.17.3:61616";
public static final String TOPIC_NAME = "topic01";

public static void main(String[] args) throws Exception{
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
Connection connection = activeMQConnectionFactory.createConnection();
connection.start();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

// 4 创建目的地 (两种 : 队列/主题 这里用主题)
Topic topic = session.createTopic(TOPIC_NAME);

MessageConsumer messageConsumer = session.createConsumer(topic);
// MessageListener接口只有一个方法,可以使用lambda表达式
messageConsumer.setMessageListener( (message) -> {
if (null != message && message instanceof TextMessage){
TextMessage textMessage = (TextMessage)message;
try {
System.out.println("****消费者text的消息:"+textMessage.getText());
}catch (JMSException e) {
}
}
});

System.in.read();
messageConsumer.close();
session.close();
connection.close();
}
}

存在多个消费者,每个消费者都能收到,自从自己启动后所有生产的消息。一定是先启动消费者或者叫订阅者,否则产生的消息没人订阅就是废消息。

控制台

topic有多个消费者时,消费消息的数量 ≈ 在线消费者数量*生产消息的数量。

下图展示了:我们先启动了3个消费者,再启动一个生产者,并生产了3条消息。

1.MQ-activemq学习笔记(上)_消息传递_33

topic和queue对比

1.MQ-activemq学习笔记(上)_消息发送_34


1.MQ-activemq学习笔记(上)_消息发送_35

JMS是什么

首先介绍一下javaee

1.MQ-activemq学习笔记(上)_java_36


什么是Java消息服务?

jms是javaee体系中的一个技术,Java消息服务指的是两个应用程序之间进行异步通信的API,它为标准协议和消息服务提供了一组通用接口,包括创建、发送、读取消息等,用于支持Java应用程序开发。在JavaEE中,当两个应用程序使用JMS进行通信时,它们之间不是直接相连的,而是通过一个共同的消息收发服务组件关联起来以达到解耦/异步削峰的效果。

1.MQ-activemq学习笔记(上)_java_37

MQ消息中间件的落地产品

1.MQ-activemq学习笔记(上)_java_38


1.MQ-activemq学习笔记(上)_java_39

对比、比较

1.MQ-activemq学习笔记(上)_java_40


大数据消息中间价,业内公认kafka,中小型公司用activemq,大型公司rocketmq就够了,毕竟经过了阿里的考验。

JMS的四大组成元素

1.MQ-activemq学习笔记(上)_java_41

消息头

JMS的消息头有哪些属性:

  • JMSDestination:消息目的地
  • JMSDeliveryMode:消息持久化模式
  • JMSExpiration:消息过期时间
  • JMSPriority:消息的优先级
  • JMSMessageID:消息的唯一标识符。后面我们会介绍如何解决幂等性。

说明: 消息的生产者可以set这些属性,消息的消费者可以get这些属性。这些属性在send方法里面也可以设置。
注意:上面这五个是常用的,并不是只有这5个。

代码实现与具体的消息说明如下:

package  com.at.activemq.topic;

import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;

public class JmsProduce_topic {

public static final String ACTIVEMQ_URL = "tcp://118.24.20.3:61626";
public static final String TOPIC_NAME = "topic01";

public static void main(String[] args) throws Exception{
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
Connection connection = activeMQConnectionFactory.createConnection();
connection.start();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Topic topic = session.createTopic(TOPIC_NAME);
MessageProducer messageProducer = session.createProducer(topic);

for (int i = 1; i < 4 ; i++) {
TextMessage textMessage = session.createTextMessage("topic_name--" + i);
// 这里可以指定每个消息的目的地
textMessage.setJMSDestination(topic);
/*
持久模式和非持久模式。
一条持久性的消息:应该被传送“一次仅仅一次”,这就意味着如果JMS提供者出现故障,该消息并不会丢失,它会在服务器恢复之后再次传递。
一条非持久的消息:最多会传递一次,这意味着服务器出现故障,该消息将会永远丢失。
*/
textMessage.setJMSDeliveryMode(0);
/*
可以设置消息在一定时间后过期,默认是永不过期。
消息过期时间,等于Destination的send方法中的timeToLive值加上发送时刻的GMT时间值。
如果timeToLive值等于0,则JMSExpiration被设为0,表示该消息永不过期。
如果发送后,在消息过期时间之后还没有被发送到目的地,则该消息被清除。
*/
textMessage.setJMSExpiration(1000);
/* 消息优先级,从0-9十个级别,0-4是普通消息5-9是加急消息。
JMS不要求MQ严格按照这十个优先级发送消息但必须保证加急消息要先于普通消息到达。默认是4级。
*/
textMessage.setJMSPriority(10);
// 唯一标识每个消息的标识。MQ会给我们默认生成一个,我们也可以自己指定。
textMessage.setJMSMessageID("ABCD");
// 上面有些属性在send方法里也能设置
messageProducer.send(textMessage);
}
messageProducer.close();
session.close();
connection.close();
System.out.println(" **** TOPIC_NAME消息发送到MQ完成 ****");
}
}

消息体

1.MQ-activemq学习笔记(上)_消息发送_42


5种消息体格式:

1.MQ-activemq学习笔记(上)_消息传递_43


相关api,生产者代码演示:

package  com.at.activemq.topic;

import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;

public class JmsProduce_topic {

public static final String ACTIVEMQ_URL = "tcp://118.24.20.3:61626";
public static final String TOPIC_NAME = "topic01";

public static void main(String[] args) throws Exception{
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
javax.jms.Connection connection = activeMQConnectionFactory.createConnection();
connection.start();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Topic topic = session.createTopic(TOPIC_NAME);
MessageProducer messageProducer = session.createProducer(topic);

for (int i = 1; i < 4 ; i++) {
// 发送TextMessage消息体
TextMessage textMessage = session.createTextMessage("topic_name--" + i);
messageProducer.send(textMessage);
// 发送MapMessage 消息体。set方法: 添加,get方式:获取
MapMessage mapMessage = session.createMapMessage();
mapMessage.setString("name", "张三"+i);
mapMessage.setInt("age", 18+i);
messageProducer.send(mapMessage);
}
messageProducer.close();
session.close();
connection.close();
System.out.println(" **** TOPIC_NAME消息发送到MQ完成 ****");
}
}

相关api,消费者代码演示,主要是处理的消息类型要严格区分且一致。

package  com.at.activemq.topic;

import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;

public class JmsConsummer_topic {
public static final String ACTIVEMQ_URL = "tcp://118.24.20.3:61626";
public static final String TOPIC_NAME = "topic01";

public static void main(String[] args) throws Exception{
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
javax.jms.Connection connection = activeMQConnectionFactory.createConnection();
connection.start();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Topic topic = session.createTopic(TOPIC_NAME);
MessageConsumer messageConsumer = session.createConsumer(topic);

messageConsumer.setMessageListener( (message) -> {
// 判断消息是哪种类型之后,再强转。
if (null != message && message instanceof TextMessage){
TextMessage textMessage = (TextMessage)message;
try {
System.out.println("****消费者text的消息:"+textMessage.getText());
}catch (JMSException e) {
}
}
if (null != message && message instanceof MapMessage){
MapMessage mapMessage = (MapMessage)message;
try {
System.out.println("****消费者的map消息:"+mapMessage.getString("name"));
System.out.println("****消费者的map消息:"+mapMessage.getInt("age"));
}catch (JMSException e) {
}
}

});
System.in.read();
messageConsumer.close();
session.close();
connection.close();
}
}

消息属性

如果需要除消息头字段之外的值,那么可以使用消息属性。他是识别/去重/重点标注等操作,非常有用的方法。

是什么?—> 他们是以属性名和属性值对的形式制定的。可以将属性是为消息头得扩展,属性指定一些消息头没有包括的附加信息,比如可以在属性里指定消息选择器。消息的属性就像可以分配给一条消息的附加消息头一样。它们允许开发者添加有关消息的不透明附加信息。它们还用于暴露消息选择器在消息过滤时使用的数据。

下图是设置消息属性的API:

1.MQ-activemq学习笔记(上)_消息发送_44

api相关展示–生产者:

package  com.at.activemq.topic;

import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;

public class JmsProduce_topic {

public static final String ACTIVEMQ_URL = "tcp://118.24.20.3:61626";
public static final String TOPIC_NAME = "topic01";

public static void main(String[] args) throws Exception{
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
Connection connection = activeMQConnectionFactory.createConnection();
connection.start();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Topic topic = session.createTopic(TOPIC_NAME);
MessageProducer messageProducer = session.createProducer(topic);

for (int i = 1; i < 4 ; i++) {
TextMessage textMessage = session.createTextMessage("topic_name--" + i);
// 调用Message的set*Property()方法,就能设置消息属性。根据value的数据类型的不同,有相应的API。
textMessage.setStringProperty("From","ZhangSan@qq.com");
textMessage.setByteProperty("Spec", (byte) 1);
textMessage.setBooleanProperty("Invalide",true);
messageProducer.send(textMessage);
}
messageProducer.close();
session.close();
connection.close();
System.out.println(" **** TOPIC_NAME消息发送到MQ完成 ****");
}
}

api相关展示–消费者:

package  com.at.activemq.topic;

import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;

public class JmsConsummer_topic {
public static final String ACTIVEMQ_URL = "tcp://118.24.20.3:61626";
public static final String TOPIC_NAME = "topic01";

public static void main(String[] args) throws Exception{
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
javax.jms.Connection connection = activeMQConnectionFactory.createConnection();
connection.start();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Topic topic = session.createTopic(TOPIC_NAME);
MessageConsumer messageConsumer = session.createConsumer(topic);

messageConsumer.setMessageListener( (message) -> {
if (null != message && message instanceof TextMessage){
TextMessage textMessage = (TextMessage)message;
try {
System.out.println("消息体:"+textMessage.getText());
System.out.println("消息属性:"+textMessage.getStringProperty("From"));
System.out.println("消息属性:"+textMessage.getByteProperty("Spec"));
System.out.println("消息属性:"+textMessage.getBooleanProperty("Invalide"));
}catch (JMSException e) {
}
}
});
System.in.read();
messageConsumer.close();
session.close();
connection.close();
}
}

消息的可靠性之queue持久化

1.MQ-activemq学习笔记(上)_java_45

可靠性从3个维度保证。

什么是持久化消息?

保证消息只被传送一次和成功使用一次。在持久性消息传送至目标时,消息服务将其放入持久性数据存储。如果消息服务由于某种原因导致失败,它可以恢复此消息并将此消息传送至相应的消费者。虽然这样增加了消息传送的开销,但却增加了可靠性。

我的理解:在消息生产者将消息成功发送给MQ消息中间件之后。无论是出现任何问题,如:MQ服务器宕机、消费者掉线等。都保证(topic要之前注册过,queue不用)消息消费者,能够成功消费消息。如果消息生产者发送消息就失败了,那么消费者也不会消费到该消息。

队列消息分位两种:持久和非持久

1.MQ-activemq学习笔记(上)_消息发送_46

默认是持久化消息

1.MQ-activemq学习笔记(上)_消息发送_47

非持久化的消费者,和之前的代码一样。下面演示非持久化的生产者。下面除灰色背景代码外,其他都和之前一样。
运行结果证明:当生产者成功发布消息之后,MQ服务端宕机重启,消息生产者就收不到该消息了

package com.at.activemq.queue;

import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;

public class JmsProduce {
public static final String ACTIVEMQ_URL = "tcp://118.24.20.3:61626";
public static final String QUEUE_NAME = "jdbc01";

public static void main(String[] args) throws Exception{
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
Connection connection = activeMQConnectionFactory.createConnection();
connection.start();
Session session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
Queue queue = session.createQueue(QUEUE_NAME);
MessageProducer messageProducer = session.createProducer(queue);
// 非持久化
messageProducer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
for (int i = 1; i < 4 ; i++) {
TextMessage textMessage = session.createTextMessage("---MessageListener---" + i);
messageProducer.send(textMessage);
}
messageProducer.close();
session.close();
connection.close();
System.out.println(" **** 消息发送到MQ完成 ****");
}
}

持久化的消费者,和之前的代码一样。下面演示持久化的生产者。下面除灰色背景代码外,其他都和之前一样。
运行结果证明:当生产者成功发布消息之后,MQ服务端宕机重启,消息生产者仍然能够收到该消息

package com.at.activemq.queue;

import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;

public class JmsProduce {
public static final String ACTIVEMQ_URL = "tcp://118.24.20.3:61626";
public static final String QUEUE_NAME = "jdbc01";

public static void main(String[] args) throws Exception{
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
Connection connection = activeMQConnectionFactory.createConnection();
connection.start();
Session session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
Queue queue = session.createQueue(QUEUE_NAME);
MessageProducer messageProducer = session.createProducer(queue);
messageProducer.setDeliveryMode(DeliveryMode.PERSISTENT);
for (int i = 1; i < 4 ; i++) {
TextMessage textMessage = session.createTextMessage("---MessageListener---" + i);
messageProducer.send(textMessage);
}
messageProducer.close();
session.close();
connection.close();
System.out.println(" **** 消息发送到MQ完成 ****");
}
}

消息的可靠性之topic持久化

1.MQ-activemq学习笔记(上)_消息传递_48