1.概念
生产者:
需要将消息发送到消费者进行异步处理的一方,通常是一个微服务的接口,上游的业务流程;
rabbitMQ队列:
由于消费者处理消息较慢,需要异步进行,该队列用于缓存消息;
消费者:
接收rabbitMQ队列发送的消息,然后进行下游业务流程处理,通常是另一个为服务的接口;
2.与其它MQ对比的优势
本人之前使用过Kafka,对比Kafka,rabbitmq配置相对简单,并且接口更加易用;
3.与其他MQ对比的劣势
参考链接:https://blog.csdn.net/weixin_34161064/article/details/93742823
个人体验:
经过一个项目的使用,体验如下:
1)消息队列容易丢失数据;
2)消息处理速度慢;
4.docker 安装
4.1
将下面的xxxxxxxxxxx替换为你拉取镜像生成的ID
docker pull rabbitmq:3.7.7-management
docker run -d --name rabbitmq3.7.7 -p 5672:5672 -p 15672:15672 -v `pwd`/data:/var/lib/rabbitmq --hostname myRabbit -e RABBITMQ_DEFAULT_VHOST=my_vhost -e RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAULT_PASS=admin xxxxxxxxxxx
4.2测试
5.springboot项目中的配置
5.1 pom
<!--消息队列依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
5.2 yml
配置参数严格按照,生成容器的参数配置
rabbitmq:
host: ${rabbit_url:127.0.0.1}
port: ${rabbit_port:5672}
username: ${rabbit_username:admin}
password: ${rabbit_password:admin}
virtual-host: my_vhost
# 设置消息的确认模式为auto
listener:
simple:
retry:
## 开启消费者重试
enabled: true
##尝试投递消息的最大数量(默认3次)
max-attempts: 10
##第一次与第二次投递尝试的时间间隔
initial-interval: 3000ms
5.2多队列配置
1)声明交换机,声明队列,声明路由,绑定队列到交换机在指定路由下
package cn.cncommdata.form.rabbitmq.config;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author libing.niu
* @description: 消息队列配置(队列声明,交换机声明,队列和交换机进行绑定)
* @date: 2019/05/07 22:04
*/
@Configuration
public class RabbitMQConfig {
/**
* 声明交换机
*/
public static final String FORM_EXCHNGE = "form_exchange";
/**
* 声明Tree的交换机
*/
public static final String TREE_EXCHANGE = "tree_exchange";
/**
* 声明审核回调队列
*/
public static final String APPROVALED_CALLBACK_TOPIC = "form_approvalCallBack";
/**
* 声明修改form工程的物料数据队列
*/
public static final String MODIFY_MATERIAL_QUEUE = "modify_material_queue";
/**
* 声明form的rountingkey
*/
public static final String FROM_ROUTING_KEY = "topic.form.callback";
/**
* 修改form工程的物料数据的路由
*/
public static final String MODIFY_MATERIAL_ROUTING_KEY = "modify.material";
/**
* 重试修改form工程的物料数据的路由
*/
public static final String MODIFY_MATERIAL_RETRY_ROUTING_KEY = "retry.modify.material";
/**
* @return 声明交换机
*/
@Bean
public TopicExchange exchange() {
return new TopicExchange(FORM_EXCHNGE);
}
/**
* @return Tree的交换机
*/
@Bean
public TopicExchange treeExchange() {
return new TopicExchange(TREE_EXCHANGE);
}
/**
* @return 修改物料数据队列
*/
@Bean
public Queue modifyMaterial() {
return new Queue(MODIFY_MATERIAL_QUEUE, true);
}
/**
* @return 修改物料数据队列
*/
@Bean
public Queue retryModifyMaterial() {
return new Queue(MODIFY_MATERIAL_RETRY_ROUTING_KEY, true);
}
/**
* @return 声明审核回调队列
*/
@Bean
public Queue approvalCallBack() {
return new Queue(RabbitMQConfig.APPROVALED_CALLBACK_TOPIC);
}
/**
* 将queueExportData队列绑定到交换机 并设置路由为topic.exportData
*
* @param approvalCallBack 回调队列
* @param exchange 交换机
* @return 返回
*/
@Bean
Binding bindingExchangeExportData(Queue approvalCallBack, TopicExchange exchange) {
return BindingBuilder.bind(approvalCallBack).to(exchange).with(FROM_ROUTING_KEY);
}
/**
* 将修改物料数据的队列和交换机进行绑定
*
* @param modifyMaterial modifyMaterial
* @param treeExchange exchange
* @return bindingExchangeModifyMaterial
*/
@Bean
Binding bindingExchangeModifyMaterial(Queue modifyMaterial, TopicExchange treeExchange) {
return BindingBuilder.bind(modifyMaterial).to(treeExchange).with(MODIFY_MATERIAL_ROUTING_KEY);
}
/**
* 将修改物料数据的队列和交换机进行绑定
*
* @param retryModifyMaterial modifyMaterial
* @param treeExchange exchange
* @return bindingExchangeModifyMaterial
*/
@Bean
Binding bindingExchangeRetryModifyMaterial(Queue retryModifyMaterial, TopicExchange treeExchange) {
return BindingBuilder.bind(retryModifyMaterial).to(treeExchange).with(MODIFY_MATERIAL_RETRY_ROUTING_KEY);
}
}
2) 发送数据到队列
import cn.cncommdata.form.rabbitmq.config.RabbitMQConfig;
import cn.cncommdata.form.service.IFormApprovalService;
import cn.cncommdata.form.service.IFormService;
import cn.cncommdata.form.service.ISaveService;
import cn.cncommdata.form.vo.BaseVO;
import cn.cncommdata.form.vo.FormDataVO;
import com.alibaba.fastjson.JSONObject;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* 审批完成后回调接口,修改源数据 -
* <p>
*
* @param tenantId 租户Id
* @param formId 表单Id
* @param dataId 数据Id
* @param result confirm审核同意/reject驳回/refuse拒绝
* @param type 审核类型 create/edit/delete
* @return baseVO
* @author libing.niu
*/
@ApiOperation("回调接口")
@GetMapping("/data/approve/callback")
public BaseVO callback(@ApiParam(value = "租户Id", required = true) @RequestHeader("tenant_id") Long tenantId,
@ApiParam(value = "表单Id", required = true) @RequestParam("form_id") Long formId,
@ApiParam(value = "数据Id", required = true) @RequestParam("data_id") Long dataId,
@ApiParam(value = "审核结果", required = true) @RequestParam String result,
@ApiParam(value = "审核类型", required = true) @RequestParam String type) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("tenantId", tenantId);
jsonObject.put("formId", formId);
jsonObject.put("dataId", dataId);
jsonObject.put("result", result);
jsonObject.put("type", type);
log.info("rabbitMQ消息:开始进入rabbitMQ队列,formDataId是==》" + dataId.toString());
rabbitTemplate.convertAndSend(RabbitMQConfig.FORM_EXCHNGE, RabbitMQConfig.FROM_ROUTING_KEY, jsonObject);
return new BaseVO(BaseVO.SUCCESS_CODE, "操作成功!");
}
3) 接收处理队列消息
package cn.cncommdata.form.rabbitmq;
import cn.cncommdata.form.rabbitmq.config.RabbitMQConfig;
import cn.cncommdata.form.service.IFormApprovalService;
import cn.cncommdata.form.util.constant.Const;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* @ClassName: ApprovalCallBackListerner
* @Description: 审核回调接口监听类
* @Author: libing.niu
* @Date: 2019/7/9 19:07
* @Version: 1.0
*/
@Slf4j
@Component
@RabbitListener(queues = RabbitMQConfig.APPROVALED_CALLBACK_TOPIC)
public class ApprovalCallBackListerner {
/**
* fromData SEVICE层接口
*/
@Autowired
private IFormApprovalService formApprovalService;
/**
* rabbitMQ异步处理 Form审批的回调业务逻辑
*
* @param jsonObject 业务参数
*/
@RabbitHandler
private void approvalCallBack(JSONObject jsonObject) {
//解析参数
Long tenantId = (Long) jsonObject.get("tenantId");
Long formId = (Long) jsonObject.get("formId");
Long dataId = (Long) jsonObject.get("dataId");
String result = (String) jsonObject.get("result");
String type = (String) jsonObject.get(Const.TYPE);
log.info("rabbitMQ消息:从rabbitMQ队列获取数据,formDataId是==》" + dataId.toString());
formApprovalService.callback(tenantId, formId, dataId, result, type);
}
}