1.消息队列使用
1.1.消息队列作用
1.1.1.流量削峰
1.1.2.提高系统的可扩展
1.1.3.提高可靠性
无法100%保证可靠
1.1.4.异步通讯
1.1.5.服务解耦
1.2.交换机,队列,绑定介绍
1.3.延迟队列介绍
应用场景:商城订单取消,火车票取消,七天自动确认收货,自动评价功能,充电桩
解决方案有两个
1,定时器
2,延迟队列
1.4.项目中如何使用消息队列
1.4.1.业务场景
用户使用手机程序扫码,产生订单,在服务器上进行余额检查,设备自检,检查通过后,下发充电指令,订单才会成功或失败。订单保存到数据库
1.4.2.解决方案
使用MQ可以应对并发问题和降低频繁操作数据库,导致性能瓶颈问题,如图-1所示。
图-1
为什么下发启动指令时,不把用户信息,设备信息也带着?
原因是设备接收的数据包有长度限制。
下发启动指令时,带着用户信息,设备信息,数据包大,流量也大。
1.5.启动rabbitMQ
1.6.安装插件
1.6.1查看插件位置
docker ps –a
docker exec -it rabbit bash
ls
cd /opt/rabbitmq
cd plugins
root@56191279a665:/opt/rabbitmq/plugins# exit
1.6.2 把插件拷贝到容器中
[root@hadoop01 ~]# cd /home
[root@hadoop01 home]# ls
app import.hql rabbitmq_delayed_message_exchange-3.9.0.ez
[root@hadoop01 home]# docker cp rabbitmq_delayed_message_exchange-3.9.0.ez rabbit:/opt/rabbitmq/plugins/
[root@hadoop01 home]# docker exec -it rabbit bash
root@56191279a665:/# cd /opt/rabbitmq/plugins/
root@56191279a665:/opt/rabbitmq/plugins# ls
enable后跟的不是ez文件名
root@56191279a665:/opt/rabbitmq/plugins# rabbitmq-plugins enable rabbitmq_delayed_message_exchange
Enabling plugins on node rabbit@56191279a665:
The following plugins have been enabled:
rabbitmq_delayed_message_exchange
started 1 plugins.
root@56191279a665:/opt/rabbitmq/plugins# exit
浏览器中访问
http://192.168.64.140:15672/
1.7.消息发送者
1.7.1.添加配置信息
在application.yml中添加
spring:
rabbitmq:
host: 192.168.64.140
port: 5672
username: guest
password: guest
virtual-host: /
connection-timeout: 15000
#设置为true后 消费者在消息没有被路由到合适队列情况下,会被消费者这边的ReturnCallback监听,不会自动删除
template:
mandatory: true
listener:
simple:
# 开启手动确认
acknowledge-mode: manual
#开启return 确认消息
publisher-returns: true
# ConfirmCallback开启发送到交换机Exchange触发回调
publisher-confirm-type: correlated
1.7.2.添加依赖
Ruoyi-admin/pom.xml reload
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
1.7.3.创建交换机,队列
创建类,写三个方法注释,写三个常量,实现三个方法
package com.ruoyi.rabbitMQ;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.CustomExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
/**
* 交换机配置类
*/
@Configuration
public class DelayExchangeConfig {
public static final String DELAY_EXCHANGE="DelayExchange";
public static final String DELAY_QUEUE="DelayQueue";
public static final String ROUTE_KEY="delay.#";
//创建交换机
@Bean
public CustomExchange getExchange(){
HashMap<String, Object> properties = new HashMap<>();
//topic是主题模式 交换机根据route key 把信息发到某个队列上。
properties.put("x-delayed-type","topic");
//x-delayed-message 在rabbit后台能看到
//Auto-delete 当最后一个绑定到Exchange 上的队列删除后,自动删除该Exchange
CustomExchange customExchange = new CustomExchange(DELAY_EXCHANGE, "x-delayed-message", false, true, properties);
return customExchange;
}
//创建队列
//org.springframework.amqp.core.Queue
@Bean
public Queue getQueue(){
Queue queue = new Queue(DELAY_QUEUE, false);
return queue;
}
//使用用route 将队列与交换机绑定
@Bean
public Binding binding(){
//创建一个对象需要设置多个参数,可以设置一个或多个,用那个设计模式解决?
Binding binding = BindingBuilder.bind(getQueue()).to(getExchange()).with(ROUTE_KEY).noargs();
return binding;
}
}
1.7.4.创建订单实体类
public class ChargingBill implements Serializable {
/** 订单号 */
private String billNumber;
/** 用户ID */
private Long userId;
/** 运营商ID */
private Long operatorId;
/** 场站ID */
private Long stationId;
/** 设备ID */
private Long deviceId;
Getter,setter
toString
1.7.5.创建service,ChargingBillController
package com.ruoyi.charge.service;
import com.ruoyi.charge.domain.ChargingBill;
public interface IChargingBillService {
public boolean createOrder(ChargingBill chargingBill);
}
package com.ruoyi.charge.service.impl;
@Service
public class ChargingBillService implements IChargingBillService {
@Override
public boolean createOrder(ChargingBill chargingBill) {
}
}
package com.ruoyi.charge.controller;
@RestController
public class ChargingBillController {
@Autowired
IChargingBillService chargingBillService;
@PostMapping("/charge/bill/createOrder")
public AjaxResult createOrder( ChargingBill chargingBill){
chargingBillService.createOrder(chargingBill);
return AjaxResult.success();
}
}
1.7.6.实现发送消息
画图分析回调,每个结果的作用
RabbitTemplate rabbitTemplate; 查看RabbitTemplate.setConfirmCallBack(),setReturnsCallback()源码,看两个接口
查看convertAndSend(String exchange, String routingKey, final Object message,
final MessagePostProcessor messagePostProcessor),看messagePostProcessor
实现createOrder()
package com.ruoyi.charge.service.impl;
import com.ruoyi.charge.domain.ChargingBill;
import com.ruoyi.charge.service.IChargingBillService;
import com.ruoyi.rabbitMQ.DelayExchangeConfig;
import org.aspectj.weaver.ast.Var;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.core.ReturnedMessage;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;
1.8.消息消费者
面试题:
消息提供者是谁?消息消费者是谁?
答的是项目名称,消息提供者是订单生成系统,消息消费者是订单处理系统
平时学习时,提供者和消费者是同一个项目。
实际项目中,消息提供者是一个项目,消息消费者是另一个项目。
学习为了省时间,把提供者和消费者放在一起。
package com.ruoyi.rabbitMQ;
import com.rabbitmq.client.Channel;
import com.ruoyi.charge.domain.ChargingBill;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;