使用场景
在实际业务中,消息有时也要区分优先级,比如定时任务产生的消息和业务请求产生的消息,定时任务的消息可以延迟消费,但是业务消息需要优先处理,避免影响流程。
实现方案
本人讲述spring boot框架下的实现方案
AmqpTemplateHelper.java
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;
@Component
public class AmqpTemplateHelper {
@Autowired
private AmqpTemplate amqpTemplate;
@Autowired
private RabbitTemplate rabbitTemplate;
/**
* 事务提交后发送MQ
* @param queue
* @param payload
* @param <T>
*/
// public <T> void send(String queue, T payload) {
// send(queue, payload, MessageProperties.DEFAULT_PRIORITY);
// }
/**
* 事务提交后发送MQ
* @param queue
* @param payload 消息内容
* @param priority 消息优先级
* @param <T>
*/
public <T> void send(String queue, T payload, Integer priority) {
if (TransactionSynchronizationManager.isSynchronizationActive()) {
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void afterCommit() {
amqpTemplate.convertAndSend(queue, payload, message -> {
message.getMessageProperties().setPriority(priority);
return message;
});
}
});
} else {
amqpTemplate.convertAndSend(queue, payload, message -> {
message.getMessageProperties().setPriority(priority);
return message;
});
}
}
/**
* 获取ready状态消息数量
*
* @param queue
* @return
*/
public int getMessageCount(String queue) {
AMQP.Queue.DeclareOk declareOk = rabbitTemplate.execute((Channel channel) -> channel.queueDeclarePassive(queue));
return declareOk.getMessageCount();
}
}
发送端
public interface AMQPConstants {
/**
* 默认优先级
*/
Integer DEFAULT_PRIORITY = 0;
/**
* 中优先级
*/
Integer MIDDLE_PRIORITY = 1;
/**
* 高优先级
*/
Integer HIGH_PRIORITY = 2;
}
amqpTemplateHelper.send(AMQPConstants.TEST, data, AMQPConstants.MIDDLE_PRIORITY);
消费端
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Argument;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class TestReceiver {
@Autowired
private TestService testService;
@RabbitListener(queuesToDeclare = @Queue(value = AMQPConstants.TEST, arguments = {
@Argument(name = "x-max-priority", value = "10", type = "java.lang.Integer")}))
public void process(Data data, Message message) {
// 如果业务逻辑还需要发送其他MQ,可以传递优先级
testService.process(data, message.getMessageProperties().getPriority());
}
}
由于rabbitMq消费端有预抓取机制,默认是250,等于消费端还是有排队,所以我们要这个参数调小一点,使优先级高的消息可以被优先抓取优先消费。
spring:
rabbitmq:
listener:
simple:
prefetch: 2