提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
简介
Rabbitmq是实现了一个 AMQP(Advanced Message Queuing Protocol)高级消息队列协议的消息队列服务,是面向消息的中间件。
四大概念
生产者:负责产生数据
交换机:接收来自生产者的消息,并将消息推送到队列中。决定消息是要推送给特定队列,还是推送给多个队列,还是丢弃。
队列:存储消息。
消费者:接收消息。
简单些,可以想象成购物,在购物平台下单后,快递员会把包裹送到你的收件人地址处。
一、主要流程
生产者(Producer)与消费者(Consumer)和 RabbitMQ 服务(Broker)建立连接, 然后生产者发布消息(Message)同时需要携带交换机(Exchange) 名称以及路由规则(Routing Key),这样消息会到达指定的交换机,然后交换机根据路由规则匹配对应的 Binding,最终将消息发送到匹配的消息队列(Quene),最后 RabbitMQ 服务将队列中的消息投递给订阅了该队列的消费者(消费者也可以主动拉取消息)。
二、RabbitTemplate的使用步骤
1.引入库
pom.xml中引入依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
2.声明队列
代码如下(示例):
/**
* description
* 客户创建审批/客户属性修改审批队列
*
* @author zzq 2023/07/14 15:07
*/
public interface CstQueueDefinition {
//客户创建工作流执行,同步代办到iflow
String IFLOW_CST_PROCESS_QUEUE = "iflowCstProcessQueue";
//客户创建工作流终止,终止iflow代办
String IFLOW_CST_END_QUEUE = "iflowCstEndQueue";
//客户创建工作流转交和加签
String IFLOW_CST_ON_DELEGATE_AND_ADD_SIGN_QUEUE = "iflowCstOnDelegateAndAddSign";
//客户创建工作流发邮件
String APPROVE_CST_EMAIL_QUEUE = "approveCstEmailQueue";
//客户属性修改工作流执行,同步代办到iflow
String IFLOW_CST_UPDATE_PROCESS_QUEUE = "iflowCstUpdateProcessQueue";
}
3.RabbitConfig配置队列、交换器
package com.h3c.pms.customer.config;
import com.h3c.pms.starter.core.config.CstQueueDefinition;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
@Component
public class RabbitConfig {
/**
/**
* Queue(String name, boolean durable, boolean exclusive, boolean
* autoDelete,Map<String, Object> arguments)
* 1、name:名称;
* 2、durable:持久性,是否持久化至硬盘(若要使队列中消息不丢失,
* 同时也需要将消息声明为持久化);
* 3、exclusive:是否声明该队列是否为连接(connection)独占,若为独占,
* 连接关闭后队列即被删除;
* 4、autoDelete:自动删除,若没有消费者订阅该队列,队列将被删除;
* 5、arguments:其他参数
* 客户创建工作流审批通过/审批拒绝
*/
@Bean
public Queue iflowCstProcessQueue() {
return new Queue(CstQueueDefinition.IFLOW_CST_PROCESS_QUEUE, true, false, false);
}
/**
* 客户创建审批终止
*/
@Bean
public Queue iflowCstEndQueue() {
return new Queue(CstQueueDefinition.IFLOW_CST_END_QUEUE, true, false, false);
}
/**
* 客户创建转交、加签
*/
@Bean
public Queue iflowCstOnDelegateAndAddSign() {
return new Queue(CstQueueDefinition.IFLOW_CST_ON_DELEGATE_AND_ADD_SIGN_QUEUE, true, false, false);
}
/**
* 客户创建工作流发邮件
*/
@Bean
public Queue approveCstEmailQueue() {
return new Queue(CstQueueDefinition.APPROVE_CST_EMAIL_QUEUE, true, false, false);
}
/**
* 客户属性修改工作流审批通过/审批拒绝
*/
@Bean
public Queue iflowCstUpdateProcessQueue() {
return new Queue(CstQueueDefinition.IFLOW_CST_UPDATE_PROCESS_QUEUE, true, false, false);
}
}
4.生产者(Producer)
import org.springframework.amqp.rabbit.core.RabbitTemplate;
@Service
@Slf4j
public class ActWorkflowServiceImpl implements ActWorkflowService {
@Autowired
private RabbitTemplate rabbitTemplate;
/**
* 审批动作后,发iflow和email
* 当前操作人工号
* 当前审批任务信息
* 当前审批用户操作信息(前端传的)
*/
@Override
public void executeAfterActivitiExecuteTaskAction(String employeeCode, ActProcTaskInfo task, TaskActionRequestExt actionRequest){
//虚拟工作流
String businessKey = task.getBusinessKey();
if(businessKey.endsWith("-Y")){
return;
}
String action = actionRequest.getAction();
//加签
if("AddSign".equalsIgnoreCase(action) || "ApproveAndAddSign".equalsIgnoreCase(action)){
ActDelegateORAddSignInfo actDelegateORAddSignInfo = new ActDelegateORAddSignInfo();
BeanUtils.copyProperties(task, actDelegateORAddSignInfo);
actDelegateORAddSignInfo.setEmployeeNums(actionRequest.getAssignList());
String jsonMsg = JSON.toJSONString(actDelegateORAddSignInfo);
if(businessKey.startsWith("ADV-")) {
rabbitTemplate.convertAndSend(AdvQueueDefinition.IFLOW_ADV_ON_DELEGATE_AND_ADD_SIGN_QUEUE, jsonMsg);
} else if(businessKey.startsWith("ORDER-")) {
rabbitTemplate.convertAndSend(OrderQueueDefinition.IFLOW_ORDER_ON_DELEGATE_AND_ADD_SIGN_QUEUE, jsonMsg);
} else if(businessKey.startsWith("LOAN-")){
log.info("借货工作流加签操作队列推送:{},值:{}",LoanQueueDefinition.IFLOW_LOAN_ON_DELEGATE_AND_ADD_SIGN_QUEUE,jsonMsg);
rabbitTemplate.convertAndSend(LoanQueueDefinition.IFLOW_LOAN_ON_DELEGATE_AND_ADD_SIGN_QUEUE, jsonMsg);
}else if(businessKey.startsWith("CST-")){
log.info("客户创建审批流加签操作队列推送:{},值:{}", CstQueueDefinition.IFLOW_CST_ON_DELEGATE_AND_ADD_SIGN_QUEUE,jsonMsg);
rabbitTemplate.convertAndSend(CstQueueDefinition.IFLOW_CST_ON_DELEGATE_AND_ADD_SIGN_QUEUE, jsonMsg);
}
return;
}
//转交
if("delegate".equalsIgnoreCase(action)){
ActDelegateORAddSignInfo actDelegateORAddSignInfo = new ActDelegateORAddSignInfo();
BeanUtils.copyProperties(task, actDelegateORAddSignInfo);
actDelegateORAddSignInfo.setEmployeeNums(Arrays.asList(actionRequest.getAssignee()));
String jsonMsg = JSON.toJSONString(actDelegateORAddSignInfo);
if(businessKey.startsWith("ADV-")) {
rabbitTemplate.convertAndSend(AdvQueueDefinition.IFLOW_ADV_ON_DELEGATE_AND_ADD_SIGN_QUEUE, jsonMsg);
} else if(businessKey.startsWith("ORDER-")) {
rabbitTemplate.convertAndSend(OrderQueueDefinition.IFLOW_ORDER_ON_DELEGATE_AND_ADD_SIGN_QUEUE, jsonMsg);
}else if(businessKey.startsWith("LOAN-")){
log.info("借货工作流delegate转交操作队列推送:{},值:{}",LoanQueueDefinition.IFLOW_LOAN_ON_DELEGATE_AND_ADD_SIGN_QUEUE,jsonMsg);
rabbitTemplate.convertAndSend(LoanQueueDefinition.IFLOW_LOAN_ON_DELEGATE_AND_ADD_SIGN_QUEUE, jsonMsg);
}
return;
}
//审批
if("complete".equalsIgnoreCase(action)){
List<org.activiti.rest.service.api.engine.variable.RestVariable> variables = actionRequest.getVariables();
String approveResult = "";
if (CollectionUtils.isNotEmpty(variables)) {
approveResult = (String) variables.stream().filter(v->"approveResult".equalsIgnoreCase(v.getName()))
.map(v->v.getValue()).findFirst().orElse("");
}
if("Rejected".equalsIgnoreCase(approveResult)){
/**
* 拒绝时终止掉流程(正常情况下会终止,但是存在并行网关时不会终止,要手动终止)
* 一开始是chenliang写的,感觉就是hzero activiti源码有bug
* 我不太懂,但是大受震撼~ 然后转手给他抄到了我这里~
*/
int actTaskCount = workflowMapper.selectCountRuTask(task.getProcInstId());
int actProcessCount = workflowMapper.selectCountNullEndTime(task.getProcInstId());
if(actTaskCount > 0 || actProcessCount > 0) {
try{
activitiService.deleteProcessInstance(task.getProcInstId());
} catch (Exception e){
log.error("出错啦:", e);
}
}
}
if("Approved".equalsIgnoreCase(approveResult) || "Rejected".equalsIgnoreCase(approveResult)){
if(businessKey.startsWith("ADV-")) {
rabbitTemplate.convertAndSend(AdvQueueDefinition.IFLOW_ADV_PROCESS_QUEUE, businessKey);
} else if(businessKey.startsWith("ORDER-")) {
rabbitTemplate.convertAndSend(OrderQueueDefinition.IFLOW_ORDER_PROCESS_QUEUE, businessKey);
String isSendEmail = LovValueHelper.getMeaningOf("H3CSYS.SYSTEM_IS_SEND_MAIL","is_send",lovAdapter);
if("1".equals(isSendEmail)) {
//报单这里有一个发邮件功能,总之先保留吧...
ActSendEmailMsg emailMsg = new ActSendEmailMsg();
emailMsg.setTaskId(task.getTaskId());
emailMsg.setProcInstId(task.getProcInstId());
emailMsg.setBusinessKey(task.getBusinessKey());
emailMsg.setTaskApproveResult(action);
emailMsg.setComment(actionRequest.getComment());
String jsonMsg = JSON.toJSONString(emailMsg);
rabbitTemplate.convertAndSend(OrderQueueDefinition.APPROVE_ORDER_EMAIL_QUEUE, jsonMsg);
}
}else if(businessKey.startsWith("LOAN-")){
log.info("借货工作流complete操作队列推送:{},值:{}",LoanQueueDefinition.IFLOW_LOAN_PROCESS_QUEUE,businessKey);
rabbitTemplate.convertAndSend(LoanQueueDefinition.IFLOW_LOAN_PROCESS_QUEUE, businessKey);
}else if(businessKey.startsWith("CST-")){
log.info("客户创建工作流complete操作队列推送:{},值:{}",CstQueueDefinition.IFLOW_CST_PROCESS_QUEUE,businessKey);
rabbitTemplate.convertAndSend(CstQueueDefinition.IFLOW_CST_PROCESS_QUEUE, businessKey);
}else if(businessKey.startsWith("CST_UPDATE-")){
log.info("客户属性修改工作流complete操作队列推送:{},值:{}",CstQueueDefinition.IFLOW_CST_UPDATE_PROCESS_QUEUE,businessKey);
rabbitTemplate.convertAndSend(CstQueueDefinition.IFLOW_CST_UPDATE_PROCESS_QUEUE, businessKey);
}
}
return;
}
}
}
5.消费者(Consumer)
package com.h3c.pms.customer.app.task;
import com.h3c.pms.customer.app.service.CstIflowService;
import com.h3c.pms.starter.core.config.CstQueueDefinition;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class IflowCstProcessConsumer {
@Autowired
private CstIflowService cstIflowService;
@RabbitListener(queues = {CstQueueDefinition.IFLOW_CST_PROCESS_QUEUE})
public void consumeMessage(String businessKey, Channel channel, Message message){
try{
System.out.println("客户新建开始消费");
cstIflowService.iflowCstProcessQueue(businessKey);
}catch (Exception e){
//@TODO 可以记个日志
log.error("出错啦:", e);
}
}
}
总结
(1)异步处理:将一些不重要的信息,适用MQ进行异步处理,较少主流程的响应时间;
(2)解耦:使用MQ转发消息,可使得服务间不再相互依赖,达到解耦的目的,提高系统灵活性,扩展性;
(3)消峰:使用MQ队列,避免高并发压垮系统、数据库、系统等,提高系统响应速度、吞吐量等;