Java 搭建 RabbitMq 消息中间件
前言
当系统中出现“生产“和“消费“的速度或稳定性等因素不一致的时候,就需要消息队列。
名词
- exchange: 交换机
- routingkey: 路由key
- queue:队列
- 控制台端口:15672
exchange和queue是需要绑定在一起的,然后消息发送到exchange再由exchange通过routingkey发送到对应的队列中。
使用场景
- 1.技能订单3分钟自动取消,改变状态
- 2.直播开始前15分钟提醒
- 3.直播状态自动结束
参考链接
https://juejin.im/entry/5a17909a518825329314397d
https://www.jianshu.com/p/ea953f633466
流程
生产者发送消息 —> order_pre_exchange交换机 —> order_per_ttl_delay_queue队列
—> 时间到期 —> order_delay_exchange交换机 —> order_delay_process_queue队列 —> 消费者
第一步:在pom文件中添加
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
第二步:在application.properties文件中添加
spring.rabbitmq.host=172.xx.xx.xxx
spring.rabbitmq.port=5672
spring.rabbitmq.username=rabbit
spring.rabbitmq.password=123456
spring.rabbitmq.virtual-host=/
spring.rabbitmq.connection-timeout=15000 spring.rabbitmq.publisher-confirms=true
spring.rabbitmq.publisher-returns=true
spring.rabbitmq.template.mandatory=true
第三步:配置 OrderQueueConfig
1 package com.tuohang.platform.config;
2
3 import org.springframework.amqp.core.Binding;
4 import org.springframework.amqp.core.BindingBuilder;
5 import org.springframework.amqp.core.DirectExchange;
6 import org.springframework.amqp.core.Queue;
7 import org.springframework.amqp.core.QueueBuilder;
8 import org.springframework.amqp.rabbit.connection.ConnectionFactory;
9 import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
10 import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter;
11 import org.springframework.context.annotation.Bean;
12 import org.springframework.context.annotation.Configuration;
13
14
15 /**
16 * rabbitMQ的队列设置(生产者发送的消息,永远是先进入exchange,再通过路由,转发到队列)
17 *
18 *
19 * @author Administrator
20 * @version 1.0
21 * @Date 2018年9月18日
22 */
23 @Configuration
24 public class OrderQueueConfig {
25
26 /**
27 * 订单缓冲交换机名称
28 */
29 public final static String ORDER_PRE_EXCHANGE_NAME = "order_pre_exchange";
30
31 /**
32 * 发送到该队列的message会在一段时间后过期进入到order_delay_process_queue 【队列里所有的message都有统一的失效时间】
33 */
34 public final static String ORDER_PRE_TTL_DELAY_QUEUE_NAME = "order_pre_ttl_delay_queue";
35
36 /**
37 * 订单的交换机DLX 名字
38 */
39 final static String ORDER_DELAY_EXCHANGE_NAME = "order_delay_exchange";
40
41 /**
42 * 订单message时间过期后进入的队列,也就是订单实际的消费队列
43 */
44 public final static String ORDER_DELAY_PROCESS_QUEUE_NAME = "order_delay_process_queue";
45
46 /**
47 * 订单在缓冲队列过期时间(毫秒)30分钟
48 */
49 public final static int ORDER_QUEUE_EXPIRATION = 1800000;
50
51 /**
52 * 订单缓冲交换机
53 *
54 * @return
55 */
56 @Bean
57 public DirectExchange preOrderExange() {
58 return new DirectExchange(ORDER_PRE_EXCHANGE_NAME);
59 }
60
61 /**
62 * 创建order_per_ttl_delay_queue队列,订单消息经过缓冲交换机,会进入该队列
63 *
64 * @return
65 */
66 @Bean
67 public Queue delayQueuePerOrderTTLQueue() {
68 return QueueBuilder.durable(ORDER_PRE_TTL_DELAY_QUEUE_NAME)
69 .withArgument("x-dead-letter-exchange", ORDER_DELAY_EXCHANGE_NAME) // DLX
70 .withArgument("x-dead-letter-routing-key", ORDER_DELAY_PROCESS_QUEUE_NAME) // dead letter携带的routing key
71 .withArgument("x-message-ttl", ORDER_QUEUE_EXPIRATION) // 设置订单队列的过期时间
72 .build();
73 }
74
75 /**
76 * 将order_pre_exchange绑定到order_pre_ttl_delay_queue队列
77 *
78 * @param delayQueuePerOrderTTLQueue
79 * @param preOrderExange
80 * @return
81 */
82 @Bean
83 public Binding queueOrderTTLBinding(Queue delayQueuePerOrderTTLQueue, DirectExchange preOrderExange) {
84 return BindingBuilder.bind(delayQueuePerOrderTTLQueue).to(preOrderExange).with(ORDER_PRE_TTL_DELAY_QUEUE_NAME);
85 }
86
87 /**
88 * 创建订单的DLX exchange
89 *
90 * @return
91 */
92 @Bean
93 public DirectExchange delayOrderExchange() {
94 return new DirectExchange(ORDER_DELAY_EXCHANGE_NAME);
95 }
96
97 /**
98 * 创建order_delay_process_queue队列,也就是订单实际消费队列
99 *
100 * @return
101 */
102 @Bean
103 public Queue delayProcessOrderQueue() {
104 return QueueBuilder.durable(ORDER_DELAY_PROCESS_QUEUE_NAME).build();
105 }
106
107 /**
108 * 将DLX绑定到实际消费队列
109 *
110 * @param delayProcessOrderQueue
111 * @param delayExchange
112 * @return
113 */
114 @Bean
115 public Binding dlxOrderBinding(Queue delayProcessOrderQueue, DirectExchange delayOrderExchange) {
116 return BindingBuilder.bind(delayProcessOrderQueue).to(delayOrderExchange).with(ORDER_DELAY_PROCESS_QUEUE_NAME);
117 }
118
119 /**
120 * 监听订单实际消费者队列order_delay_process_queue
121 *
122 * @param connectionFactory
123 * @param processReceiver
124 * @return
125 */
126 @Bean
127 public SimpleMessageListenerContainer orderProcessContainer(ConnectionFactory connectionFactory,
128 OrderProcessReceiver processReceiver) {
129 SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
130 container.setConnectionFactory(connectionFactory);
131 container.setQueueNames(ORDER_DELAY_PROCESS_QUEUE_NAME); // 监听order_delay_process_queue
132 container.setMessageListener(new MessageListenerAdapter(processReceiver));
133 return container;
134 }
135 }
消费者 OrderProcessReceiver :
1 package com.tuohang.platform.config;
2
3 import java.util.Objects;
4
5 import org.apache.tools.ant.types.resources.selectors.Date;
6 import org.slf4j.Logger;
7 import org.slf4j.LoggerFactory;
8 import org.springframework.amqp.core.Message;
9 import org.springframework.amqp.rabbit.core.ChannelAwareMessageListener;
10 import org.springframework.stereotype.Component;
11 import com.rabbitmq.client.Channel;
12
13 /**
14 * 订单延迟处理消费者
15 *
16 *
17 * @author Administrator
18 * @version 1.0
19 * @Date 2018年9月18日
20 */
21 @Component
22 public class OrderProcessReceiver implements ChannelAwareMessageListener {
23
24 private static Logger logger = LoggerFactory.getLogger(OrderProcessReceiver.class);
25
26 String msg = "The failed message will auto retry after a certain delay";
27
28 @Override
29 public void onMessage(Message message, Channel channel) throws Exception {
30 try {
31 processMessage(message);
32 } catch (Exception e) {
33 // 如果发生了异常,则将该消息重定向到缓冲队列,会在一定延迟之后自动重做
34 channel.basicPublish(OrderQueueConfig.ORDER_PRE_EXCHANGE_NAME, OrderQueueConfig.ORDER_PRE_TTL_DELAY_QUEUE_NAME, null,
35 msg.getBytes());
36 }
37 }
38
39 /**
40 * 处理订单消息,如果订单未支付,取消订单(如果当消息内容为FAIL_MESSAGE的话,则需要抛出异常)
41 *
42 * @param message
43 * @throws Exception
44 */
45 public void processMessage(Message message) throws Exception {
46 String realMessage = new String(message.getBody());
47 logger.info("Received <" + realMessage + ">");
48 // 取消订单
49 if(!Objects.equals(realMessage, msg)) {
50 // SpringKit.getBean(ITestService.class).resetSexById(Long.valueOf(realMessage));
51 System.out.println("测试111111-----------"+new Date());
52 System.out.println(message);
53 }
54 }
55 }
或者
1 /**
2 * 测试 rabbit 消费者
3 *
4 *
5 * @author Administrator
6 * @version 1.0
7 * @Date 2018年9月25日
8 */
9 @Component
10 @RabbitListener(queues = TestQueueConfig.TEST_DELAY_PROCESS_QUEUE_NAME)
11 public class TestProcessReceiver {
12
13 private static Logger logger = LoggerFactory.getLogger(TestProcessReceiver.class);
14
15 String msg = "The failed message will auto retry after a certain delay";
16
17 @RabbitHandler
18 public void onMessage(Message message, Channel channel) throws Exception {
19 try {
20 processMessage(message);
21 //告诉服务器收到这条消息 已经被我消费了 可以在队列删掉;否则消息服务器以为这条消息没处理掉 后续还会在发
22 channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
23 } catch (Exception e) {
24 // 如果发生了异常,则将该消息重定向到缓冲队列,会在一定延迟之后自动重做
25 channel.basicPublish(TestQueueConfig.TEST_PRE_EXCHANGE_NAME, TestQueueConfig.TEST_PRE_TTL_DELAY_QUEUE_NAME, null,
26 msg.getBytes());
27 }
28 }
29
30 /**
31 * 处理订单消息,如果订单未支付,取消订单(如果当消息内容为FAIL_MESSAGE的话,则需要抛出异常)
32 *
33 * @param message
34 * @throws Exception
35 */
36 public void processMessage(Message message) throws Exception {
37 String realMessage = new String(message.getBody());
38 logger.info("Received < " + realMessage + " >");
39 // 取消订单
40 if(!Objects.equals(realMessage, msg)) {
41 System.out.println("测试111111-----------"+new Date());
42 }else {
43 System.out.println("rabbit else...");
44 }
45 }
46 }
生产者
1 /**
2 * 测试rabbitmq
3 *
4 * @return
5 */
6 @RequestMapping(value = "/testrab")
7 public String testraa() {
8 GenericResult gr = null;
9 try {
10 String name = "test_pre_ttl_delay_queue";
11 long expiration = 10000;//10s 过期时间
12 rabbitTemplate.convertAndSend(name,String.valueOf(123456));
13 // 在单个消息上设置过期时间
14 //rabbitTemplate.convertAndSend(name,(Object)String.valueOf(123456), new ExpirationMessagePostProcessor(expiration));
15
16
17 } catch (ServiceException e) {
18 e.printStackTrace();
19 gr = new GenericResult(StateCode.ERROR, languageMap.get("network_error"), e.getMessage());
20 }
21
22 return getWrite(gr);
23 }
Java 搭建 RabbitMq 消息中间件的更多相关文章
- CentOS6.8搭建rabbitmq消息中间件
参考资料:http://blog.csdn.net/yunfeng482/article/details/72853983 一.rabbitmq简介 MQ全称为Message Queue, 消息队列( ...
- spring boot / cloud (九) 使用rabbitmq消息中间件
spring boot / cloud (九) 使用rabbitmq消息中间件 前言 rabbitmq介绍: RabbitMQ是一个在AMQP基础上完整的,可复用的企业消息系统.它可以用于大型软件系统 ...
- 搭建 RabbitMQ Server 高可用集群
阅读目录: 准备工作 搭建 RabbitMQ Server 单机版 RabbitMQ Server 高可用集群相关概念 搭建 RabbitMQ Server 高可用集群 搭建 HAProxy 负载均衡 ...
- 搭建 RabbitMQ Server 高可用集群【转】
阅读目录: 准备工作 搭建 RabbitMQ Server 单机版 RabbitMQ Server 高可用集群相关概念 搭建 RabbitMQ Server 高可用集群 搭建 HAProxy 负载均衡 ...
- Docker:搭建RabbitMQ集群
RabbitMQ原理介绍(一) RabbitMQ安装使用(二) RabbitMQ添加新用户并支持远程访问(三) RabbitMQ管理命令rabbitmqctl详解(四) RabbitMQ两种集群模式配 ...
- 搭建RabbitMQ集群(Docker)
前一篇搭建RabbitMQ集群(通用)只是把笔记直接移动过来了,因为我的机器硬盘已经满了,实在是开不了那么虚拟机. 还好,我的Linux中安装了Docker,这篇文章就简单介绍一下Docker中搭建R ...
- Docker搭建RabbitMQ集群
Docker搭建RabbitMQ集群 Docker安装 见官网 RabbitMQ镜像下载及配置 见此博文 集群搭建 首先,我们需要启动运行RabbitMQ docker run -d --hostna ...
- java 搭建新项目,最佳组合:spring boot + mybatis generator
java 搭建新项目,最佳组合:spring boot + mybatis generator
- RabbitMQ学习(二):Java使用RabbitMQ要点知识
转 https://blog.csdn.net/leixiaotao_java/article/details/78924863 1.maven依赖 <dependency> <g ...
随机推荐
- 2018-2019 ACM-ICPC, NEERC, Southern Subregional Contest, Qualification Stage(11/12)
2018-2019 ACM-ICPC, NEERC, Southern Subregional Contest, Qualification Stage A. Coffee Break 排序之后优先队 ...
- zjnu1757Excellent (数学公式)
Description Let us begin with a positive integer N and find the smallest positive integer which does ...
- 【noi 2.6_9272】偶数个数字3(DP)
题意:问所有的N位数中,有多少个有偶数个数字3的数. 解法:f[i][j]表示i位数中含数字3的个数模2为j的个数.于是分第i位填3还是不填3讨论. 小tip:要模12345:for循环新定义了一个变 ...
- aop详解与实战
1. 什么是AOP aop:面向切面编程.采用横向机制. oop:面向对象编程.采用纵向机制. AOP,面向切面编程.就是通过某个切入点(比如方法开始.结束)向某个切面(被切的对象)切入环绕通知(需要 ...
- C语言之库函数的模拟与使用
C语言之库函数的模拟与使用 在我们学习C语言的过程中,难免会遇到这样的一种情况: 我们通常实现一个功能的时候,费尽心血的写出来,却有着满满的错,这时却有人来告诉你说:这个功能可以用相应的库函数来实现. ...
- 2018大都会赛 A Fruit Ninja【随机数】
题目链接:戳这里 题意:一个平面里有n个点,问存不存在一条直线上有m个点,满足m >= n*x. 解题思路:0<x<1,且x小数点后只有1位,也就是说10*m > n.假设存在 ...
- Python源码剖析——02虚拟机
<Python源码剖析>笔记 第七章:编译结果 1.大概过程 运行一个Python程序会经历以下几个步骤: 由解释器对源文件(.py)进行编译,得到字节码(.pyc文件) 然后由虚拟机按照 ...
- c# App.xaml
随着wpf自动创建的,是项目的起始点..Net先再App里找,找到了window然后开启window,项目真正的起始点是在App里. 这两个 (App 的xaml和cs文件)和MainWindow 的 ...
- CSS3 动态生成内容(在Web中插入内容)====CSS的伪类或者伪元素
# css3 .类:伪类::伪元素 /* CSS3伪元素/伪类 :https://www.w3.org/TR/css3-selectors/#selectors ::selection 伪元素(F12 ...
- 经济学,金融学:资产证券化 ABS
经济学,金融学:资产证券化 ABS ABS 资产支持证券 蚂蚁金服如何把30亿变成3000亿?资产证券化 前几天,花呗借呗的东家蚂蚁集团在上市前夕被监管部门叫停,因为这则新闻广大网民都听说了一个概念: ...