1、RabbitMQ介绍

可参照RabbitMQ笔记

2、接入配置

pom依赖

<!--amqp依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

配置文件

server.port=8080

spring.application.name=springboot-rabbitmq
spring.rabbitmq.host=192.168.242.131
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
# 开启发送确认
spring.rabbitmq.publisher-confirms=true
# 开启发送失败退回
spring.rabbitmq.publisher-returns=true
# 开启ACK
spring.rabbitmq.listener.direct.acknowledge-mode=manual
spring.rabbitmq.listener.simple.acknowledge-mode=manual

3、一对一模式

  即一个生产者对一个消费者模式

配置类

@Configuration
public class RabbitMqConfig { @Bean
public Queue kinsonQueue() {
return new Queue("kinson");
} }

消费者

@Component
//监听队列kinson
@RabbitListener(queues = {"kinson"})
public class MyReceiver1 { @RabbitHandler
public void receiver(String msg) {
System.out.println("MyReceiver1 :" + msg);
}
}

消息生产者测试接口

    /**
* 单条消息发送给单个队列,该队列只有一个消费者
*
* @return
*/
@GetMapping(value = "send")
public String send() {
String content = "Date:" + System.currentTimeMillis();
//发送默认交换机对应的的队列kinson
amqpTemplate.convertAndSend("kinson", content);
return content;
}

4、一对多模式

  即一个生产者对多个消费者,该模式下可以是一个生产者将消息投递到一个队列,该队列对应多个消费者,此时每条消息只会被消费一次,多个消费者循环处理。另外也可以是一个生产者将消息投递到多个队列里,此时消息是被复制处理。

模式一:

配置类

@Configuration
public class RabbitMqConfig { @Bean
public Queue kinsonQueue() {
return new Queue("kinson");
} }

消费者1

@Component
//监听队列kinson
@RabbitListener(queues = {"kinson"})
public class MyReceiver1 { @RabbitHandler
public void receiver(String msg) {
System.out.println("MyReceiver1 :" + msg);
}
}

消费者2

@Component
//监听队列kinson
@RabbitListener(queues = {"kinson"})
public class MyReceiver2 { @RabbitHandler
public void receiver(String msg) {
System.out.println("MyReceiver2 :" + msg);
}
}

消息生产者测试接口

    /**
* 发送多条消息到一个队列,该队列有多个消费者
*
* @return
*/
@GetMapping(value = "sendMore")
public String sendMore() {
List<String> result = new ArrayList<String>();
//发送10条数据
for (int i = 0; i < 10; i++) {
String content = "第" + (i + 1) + "次发送 Date:" + System.currentTimeMillis();
//发送默认交换机对应的的队列kinson,此时有两个消费者MyReceiver1和MyReceiver2,每条消息只会被消费一次
amqpTemplate.convertAndSend("kinson", content);
result.add(content);
}
return String.join("<br/>", result);
}

模式二:

配置类

@Configuration
public class RabbitMqConfig { @Bean
public Queue kinsonQueue() {
return new Queue("kinson");
} @Bean
public Queue kinsonQueue2() {
return new Queue("kinson2");
}
}

kinson队列消费者

@Component
//监听队列kinson
@RabbitListener(queues = {"kinson"})
public class MyReceiver1 { @RabbitHandler
public void receiver(String msg) {
System.out.println("MyReceiver1 :" + msg);
}
}

kinson2队列消费者

@Component
//监听队列kinson2
@RabbitListener(queues = {"kinson2"})
public class MyReceiver3 { @RabbitHandler
public void receiver(String msg) {
System.out.println("MyReceiver3 :" + msg);
}
}

消息生产者测试接口

  /**
* 发送多条消息到多个队列
*
* @return
*/
@GetMapping(value = "sendMoreQueue")
public String sendMoreQueue() {
List<String> result = new ArrayList<String>();
//发送10条数据
for (int i = 0; i < 10; i++) {
String content = "第" + (i + 1) + "次发送 Date:" + System.currentTimeMillis();
//发送默认交换机对应的的队列kinson
amqpTemplate.convertAndSend("kinson", content);
//发送默认交换机对应的的队列kinson2
amqpTemplate.convertAndSend("kinson2", content);
result.add(content);
}
return String.join("<br/>", result);
}

相应测试结果请自测

5、ACK消息确认

配置文件加入相应配置

# 开启发送确认
spring.rabbitmq.publisher-confirms=true
# 开启发送失败退回
spring.rabbitmq.publisher-returns=true
# 开启ACK
spring.rabbitmq.listener.direct.acknowledge-mode=manual
spring.rabbitmq.listener.simple.acknowledge-mode=manual

配置类,使用Fanout类型的Exchange,主要是设置队列,交换机及绑定

@Configuration
public class RabbitMqFanoutACKConfig { @Bean
public Queue ackQueue() {
return new Queue("ackQueue");
} @Bean
FanoutExchange fanoutExchange() {
return new FanoutExchange("fanoutExchange");
} @Bean
Binding bindingAckQueue2Exchange(Queue ackQueue, FanoutExchange fanoutExchange) {
return BindingBuilder.bind(ackQueue).to(fanoutExchange);
} }

消息发送服务

@Service
public class AckSenderService implements RabbitTemplate.ReturnCallback { @Autowired
private RabbitTemplate rabbitTemplate; @Override
public void returnedMessage(Message message, int i, String s, String s1, String s2) {
System.out.println("AckSender returnedMessage " + message.toString() + " === " + i + " === " + s1 + " === " + s2);
} /**
* 消息发送
*/
public void send() {
final String content = "现在时间是" + LocalDateTime.now(ZoneId.systemDefault()); //设置返回回调
rabbitTemplate.setReturnCallback(this);
//设置确认回调
rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
if (ack) {
System.out.println("消息发送成功!");
}
else {
System.out.println("消息发送失败," + cause + correlationData.toString());
}
});
rabbitTemplate.convertAndSend("ackQueue", content);
}
}

消息消费者

@Component
@RabbitListener(queues = {"ackQueue"})
public class MyAckReceiver { @RabbitHandler
public void process(String sendMsg, Channel channel, Message message) { System.out.println("AckReceiver : 收到发送消息 " + sendMsg + ",收到消息时间"
+ LocalDateTime.now(ZoneId.systemDefault())); try {
//告诉服务器收到这条消息已经被当前消费者消费了,可以在队列安全删除,这样后面就不会再重发了,
//否则消息服务器以为这条消息没处理掉,后续还会再发
//第二个参数是消息的标识,false只确认当前一个消息收到,true确认所有consumer获得的消息
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
System.out.println("process success");
} catch (Exception e) {
System.out.println("process fail");
e.printStackTrace();
} }
}

测试访问接口

   /**
* @return
*/
@GetMapping(value = "ackSend")
public String ackSend() {
senderService.send(); return "ok";
}

测试将Consumer确认代码注释掉,即

@Component
@RabbitListener(queues = {"ackQueue"})
public class MyAckReceiver { @RabbitHandler
public void process(String sendMsg, Channel channel, Message message) { System.out.println("AckReceiver : 收到发送消息 " + sendMsg + ",收到消息时间"
+ LocalDateTime.now(ZoneId.systemDefault())); try {
//告诉服务器收到这条消息已经被当前消费者消费了,可以在队列安全删除,这样后面就不会再重发了,
//否则消息服务器以为这条消息没处理掉,后续还会再发
//第二个参数是消息的标识,false只确认当前一个消息收到,true确认所有consumer获得的消息
//channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
System.out.println("process success");
} catch (Exception e) {
System.out.println("process fail");
e.printStackTrace();
} }
}

此时访问测试接口,可以看到当消息发送完被消费掉之后,队列的状态变为unacked。

当停掉服务时,unacked状态变为Ready

再重新启动服务时会重新发送消息

6、事务机制

事务的实现主要是对信道(Channel)的设置,主要的方法有三个:
//声明启动事务模式
channel.txSelect();
//提交事务
channel.txComment();
//回滚事务
channel.txRollback();

消息发送示例

public void publish()
throws KeyManagementException, NoSuchAlgorithmException, URISyntaxException, IOException, TimeoutException {
// 创建连接
ConnectionFactory factory = new ConnectionFactory();
factory.setUsername(username);
factory.setPassword(password);
factory.setVirtualHost("/");
factory.setHost(host);
factory.setPort(port);
Connection conn = factory.newConnection();
// 创建信道
Channel channel = conn.createChannel();
// 声明队列
channel.queueDeclare(TX_QUEUE, true, false, false, null); try { long startTime = System.currentTimeMillis(); for (int i = 0; i < 10; i++) {
// 声明事务
channel.txSelect();
String message = String.format("时间 => %s", System.currentTimeMillis());
// 发送消息
channel.basicPublish("", TX_QUEUE, MessageProperties.PERSISTENT_TEXT_PLAIN,
message.getBytes("UTF-8"));
// 提交事务
channel.txCommit();
} long endTime = System.currentTimeMillis(); System.out.println("事务模式,发送10条数据,执行花费时间:" + (endTime - startTime) + "s"); } catch (Exception e) {
channel.txRollback();
} finally {
channel.close();
conn.close();
}
}

消息消费示例

public void consume() throws IOException, TimeoutException, InterruptedException {

        Connection conn = RabbitMqConnFactoryUtil.getRabbitConn();
Channel channel = conn.createChannel();
channel.queueDeclare(TX_QUEUE, true, false, false, null);
// 声明事务
channel.txSelect();
try {
//单条消息获取进行消费
GetResponse resp = channel.basicGet(TX_QUEUE, false);
String message = new String(resp.getBody(), "UTF-8");
System.out.println("收到消息:" + message);
//消息拒绝
// channel.basicReject(resp.getEnvelope().getDeliveryTag(), true);
// 消息确认
channel.basicAck(resp.getEnvelope().getDeliveryTag(), false);
// 提交事务
channel.txCommit();
} catch (Exception e) {
// 回滚事务
channel.txRollback();
} finally {
//关闭通道、连接
channel.close();
conn.close();
}
}

7、Confirm消息确认

Confirm发送方确认模式使用和事务类似,也是通过设置Channel进行发送方确认的,Confirm的三种实现方式:
//方式一:普通发送方确认模式
channel.waitForConfirms();
//方式二:批量确认模式
channel.waitForConfirmsOrDie();
//方式三:异步监听发送方确认模式
channel.addConfirmListener();

消息发布示例

public void publish() throws IOException, TimeoutException, InterruptedException {
// 创建连接
ConnectionFactory factory = new ConnectionFactory();
factory.setUsername(username);
factory.setPassword(password);
factory.setVirtualHost("/");
factory.setHost(host);
factory.setPort(port);
Connection conn = factory.newConnection();
// 创建信道
Channel channel = conn.createChannel();
// 声明队列
channel.queueDeclare(CONFIRM_QUEUE, false, false, false, null); long startTime = System.currentTimeMillis(); for (int i = 0; i < 10; i++) {
// 开启发送方确认模式
channel.confirmSelect();
String message = String.format("时间 => %s", System.currentTimeMillis());
channel.basicPublish("", CONFIRM_QUEUE, null, message.getBytes("UTF-8"));
} //添加确认监听器
channel.addConfirmListener(new ConfirmListener() { @Override
public void handleNack(long deliveryTag, boolean multiple) throws IOException {
System.out.println("未确认消息,标识:" + deliveryTag);
} @Override
public void handleAck(long deliveryTag, boolean multiple) throws IOException {
System.out.println(String.format("已确认消息,标识:%d,多个消息:%b", deliveryTag, multiple));
}
}); long endTime = System.currentTimeMillis(); System.out.println("执行花费时间:" + (endTime - startTime) + "s"); }

RabbitMQ简单示例源码参照Github

Springboot2.x整合RabbitMQ的更多相关文章

  1. SpringBoot2.0应用(三):SpringBoot2.0整合RabbitMQ

    如何整合RabbitMQ 1.添加spring-boot-starter-amqp <dependency> <groupId>org.springframework.boot ...

  2. SpringBoot2.0源码分析(三):整合RabbitMQ分析

    SpringBoot具体整合rabbitMQ可参考:SpringBoot2.0应用(三):SpringBoot2.0整合RabbitMQ RabbitMQ自动注入 当项目中存在org.springfr ...

  3. 【SpringBoot】息队列介绍和SpringBoot2.x整合RockketMQ、ActiveMQ

    ========================13.消息队列介绍和SpringBoot2.x整合RockketMQ.ActiveMQ ======================= 1.JMS介绍和 ...

  4. springboot 学习之路 20 (整合RabbitMQ)

    整合RabbitMQ: 我的操作系统是window7 ,所以在整合ribbotMQ之前需要先安装rabbitMq服务:安装步骤请参考:window下安装RabbitMQ  这个详细介绍了安装步骤,请按 ...

  5. 消息队列介绍和SpringBoot2.x整合RockketMQ、ActiveMQ 9节课

    1.JMS介绍和使用场景及基础编程模型     简介:讲解什么是小写队列,JMS的基础知识和使用场景     1.什么是JMS: Java消息服务(Java Message Service),Java ...

  6. spring boot实战(第十二篇)整合RabbitMQ

    前言 最近几篇文章将围绕消息中间件RabbitMQ展开,对于RabbitMQ基本概念这里不阐述,主要讲解RabbitMQ的基本用法.Java客户端API介绍.spring Boot与RabbitMQ整 ...

  7. 【RabbitMQ系列】 Spring mvc整合RabbitMQ

    一.linux下安装rabbitmq 1.安装erlang环境 wget http://erlang.org/download/otp_src_18.2.1.tar.gz tar xvfz otp_s ...

  8. Spring Boot 整合 rabbitmq

    一.消息中间件的应用场景 异步处理 场景:用户注册,信息写入数据库后,需要给用户发送注册成功的邮件,再发送注册成功的邮件. 1.同步调用:注册成功后,顺序执行发送邮件方法,发送短信方法,最后响应用户 ...

  9. 每天学点SpringCloud(十三):SpringCloud-Stream整合RabbitMQ

    我们知道,当微服务越来越来多的时候,仅仅是feign的http调用方式已经满足不了我们的使用场景了.这个时候系统就需要接入消息中间件了.相比较于传统的Spring项目.SpringBoot项目使用消息 ...

随机推荐

  1. [转]Android ImageView的scaleType属性与adjustViewBounds属性

    Android ImageView的scaleType属性与adjustViewBounds属性   ImageView的scaleType的属性有好几种,分别是matrix(默认).center.c ...

  2. F-maximum clique 1_2019牛客暑期多校训练营(第五场)

    题意 给出n个不同的数字\(a_i\),求出最大的子集,使得子集内任意两个数在二进制下至少有两位不同. 题解 先对任意两个二进制位只有一个不同的两个数连边,那么问题就转化成找出最多的点集,任意两点没有 ...

  3. 共价大爷游长沙 lct 维护子树信息

    这个题目的关键就是判断 大爷所有可能会走的路 会不会经过询问的边. 某一条路径经过其中的一条边, 那么2个端点是在这条边的2测的. 现在我们要判断所有的路径是不是都经过 u -> v 我们以u为 ...

  4. Codeforces Round #479 (Div. 3) B. Two-gram

    原题代码:http://codeforces.com/contest/977/problem/B 题解:有n个字符组成的字符串,输出出现次数两个字符组合.例如第二组样例ZZ出现了两次. 方法:比较无脑 ...

  5. 字符串的api

    一.基础 1.字符串.charAt(index) 根据下标获取字符串的某一个字符 应用: 判断字符串的首字母是否大写 任意给定的一串字母,统计字符串里面的大写字母和小写字母的个数 2.字符串.inde ...

  6. 【Offer】[53-1] 【数字在排序数组中出现的次数】

    题目描述 思路分析 测试用例 Java代码 代码链接 题目描述 统计一个数字在排序数组中出现的次数.例如,输入排序数组{1,2,3,3,3,3,4,5}和数字3,由于3在这个数组中出现了4次,因此输出 ...

  7. 【Spring】事务

    一.数据库事务概述 二.Spring中事务 1. Spring 事务管理: 2. Spring 事务管理的API: 2.1 API概述 2.2 PlatformTransactionManager 接 ...

  8. java路障CyclicBarrier

    当所有线程都执行到某行代码,才可已往下执行: package threadLock; import java.util.Random; import java.util.concurrent.Brok ...

  9. python科学计算与可视化视频教程

    目录: 下载链接:https://www.yinxiangit.com/616.html 第一单元TVTK入门-1.mp4第一单元TVTK入门-2.mp4第一单元TVTK入门-3.mp4 第一单元TV ...

  10. Linux执行后台work相关

    Linux的后台运行.关闭.查看后台任务 & ctrl+z jobs fg bg kill nohup setsid disown screen 1.& 加在命令的最后,可以把命令放到 ...