RabbitMq使用延迟队列
配置文件
spring:
rabbitmq:
host: 127.0.0.1
port: 5672
username: guest
password: guest
publisher-confirms: true
virtual-host: /
template:
mandatory: true
listener:
simple:
acknowledge-mode: manual
max-concurrency: 1
concurrency: 1
direct:
retry:
enabled: true
publisher-returns: true
先定义RabbitMqConfig类
@Configuration
@Component
@ConfigurationProperties(prefix = "spring.rabbitmq")
@Slf4j
public class RabbitMqConfig {
private String host;
private int port;
private String userName;
private String password;
public boolean isMandatory() {
return mandatory;
}
public void setMandatory(boolean mandatory) {
this.mandatory = mandatory;
}
private boolean mandatory;
@Bean
public ConnectionFactory connectionFactory() {
CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory(host,port);
cachingConnectionFactory.setUsername(userName);
cachingConnectionFactory.setPassword(password);
cachingConnectionFactory.setVirtualHost("/");
//设置消息回调必须设置为TRUE
cachingConnectionFactory.setPublisherConfirms(true);
return cachingConnectionFactory;
}
@Bean
/** 因为要设置回调类,所以应是prototype类型,如果是singleton类型,则回调类为最后一次设置 */
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public RabbitTemplate rabbitTemplate() {
RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory());
rabbitTemplate.setMandatory(mandatory); // 开启消息返回模式
rabbitTemplate.setConfirmCallback(new CallBackSender());
rabbitTemplate.setReturnCallback(new CallBackSender());
return rabbitTemplate;
}
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
//定义队列
/**
* 订单队列
* @return
*/
@Bean
public Queue orderQueue() {
Queue queue = new Queue("order_queue", true);
return queue;
}
//定义一个交换机
@Bean
public CustomExchange delayExchange3() {
Map<String, Object> args = new HashMap<>();
args.put("x-delayed-type", "direct");
return new CustomExchange("order_exchange", "x-delayed-message",true, false,args);
}
//绑定队列与交换机
@Bean
public Binding binding() {
return BindingBuilder.bind(orderQueue()).to(delayExchange3()).with("order_queue").noargs();
}
}
2.定义一个 callbacksend 使用ack模式
@Component
public class CallBackSender implements RabbitTemplate.ConfirmCallback, RabbitTemplate.ReturnCallback {
@Override
public void confirm(CorrelationData correlationData, boolean ack, String cause) {
System.out.println("ack = " + ack);
if (ack) { //如果消息发送成功
System.out.println("消息[" + correlationData.getId() + "]成功发送到指定ExChange");
//
} else {
System.out.println("消息[" + correlationData.getId() + "]发送到ExChange失败:" + cause);
}
}
@Override
public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
System.out.println("消息未能成功路由到指定queues");
System.out.println("return--message:" + new String(message.getBody()) + ",replyCode:" + replyCode
+ ",replyText:" + replyText + ",exchange:" + exchange + ",routingKey:" + routingKey);
}
}
3.创建发送信息业务类
@Service
public class MessageServiceImpl {
@Autowired
private RabbitTemplate rabbitTemplate;
public void sendMsg(String routingKey,String msg,String exchange,Long time) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("消息发送时间:"+sdf.format(new Date()));
CorrelationData correlationData =new CorrelationData();
correlationData.setId(StringUtils.getUUID());
rabbitTemplate.convertAndSend(exchange, routingKey, msg, message -> {
message.getMessageProperties().setHeader("x-delay",time);
// message.getMessageProperties().setDelay(time.intValue());
return message;
},correlationData);
}
}
4.创建测试类
@RunWith(SpringRunner.class)
@SpringBootTest
public class RabbitmqApplicationTests {
@Autowired
private MessageServiceImpl messageService;
@Test
public void send() {
Order order=new Order();
order.setOrderId(StringUtils.getUUID());
JSON.toJSONString(order);
messageService.sendMsg("order_queue",JSON.toJSONString(order),"order_exchange",1*60*1000L);
}
}
5.创建消息监听类
@Component
@Slf4j
public class MessageReceiver {
@RabbitListener(queues = "order_queue")
public void receiveOrder(String msg,Message message, Channel channel) throws IOException {
JSONObject obj= JSONObject.fromObject(msg);
String id=obj.getString("orderId");
Order order=orderService.getById(id);
try {
//每次消息正确应答+1
long deliverTag = message.getMessageProperties().getDeliveryTag();
if (deliverTag % 2 == 0) {
log.error("消息处理失败,重新返回队列");
throw new Exception("数据处理错误");
}
//执行自己的业务代码
System.out.println("接收到的消息:"+msg);
//通知服务器此消息已经被消费,可从队列删掉, 这样以后就不会重发,否则后续还会在发
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
} catch (Exception e) {
e.printStackTrace();
/**
* basicAck 方法的第二个参数 multiple 取值为 false 时,表示通知 RabbitMQ 当前消息被确认
*/
channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
}
}
}