使用Spring AMQP - spring-amqp with Spring Boot
我在这里尝试实施死信交换。我正在向队列发送消息,如果发生某些业务异常,那么它应该将消息发送到“dlq”队列并在那里等待5秒然后它应该进入队列再次处理..... 5次尝试之后应该从容器里出来。
请找到配置
application.yml
spring:
rabbitmq:
host: localhost
username: guest
password: guest
port: 5672
server:
port: 8081
MQ Config
import java.util.HashMap;
import java.util.Map;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MQConfig {
// public static final String OUTGOING_QUEUE = "outgoing.example";
// public static final String INCOMING_QUEUE = "incoming.example";
@Autowired
private ConnectionFactory cachingConnectionFactory;
// Setting the annotation listeners to use the jackson2JsonMessageConverter
@Bean
public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory() {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(cachingConnectionFactory);
factory.setMessageConverter(jackson2JsonMessageConverter());
return factory;
}
// Standardize on a single objectMapper for all message queue items
@Bean
public Jackson2JsonMessageConverter jackson2JsonMessageConverter() {
return new Jackson2JsonMessageConverter();
}
@Bean
public Queue outgoingQueue() {
Map<String, Object> args = new HashMap<String, Object>();
// The default exchange
args.put("x-dead-letter-exchange", "dlx");
// Route to the incoming queue when the TTL occurs
// args.put("x-dead-letter-routing-key", "q.with.dlx");
// TTL 5 seconds
args.put("x-message-ttl", 5000);
return new Queue("q.with.dlx", false, false, false, args);
}
@Bean
public RabbitTemplate rabbitTemplate() {
RabbitTemplate rabbitTemplate = new RabbitTemplate(cachingConnectionFactory);
rabbitTemplate.setMessageConverter(jackson2JsonMessageConverter());
return rabbitTemplate;
}
@Bean
public Queue incomingQueue() {
return new Queue("dlq");
}
@Bean
public DirectExchange directExchange() {
return new DirectExchange("dlx") ;
}
@Bean
public Binding binding(Queue incomingQueue, DirectExchange directExchange) {
return BindingBuilder.bind(incomingQueue()).to(directExchange()).with("q.with.dlx");
}
发布商
import java.util.Date;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.spring.amqp.domain.ExampleObject;
@Component
@RestController
@RequestMapping("/publish")
public class Publisher {
@Autowired
private RabbitTemplate rabbitTemplate;
// Scheduled task to send an object every 5 seconds
// @Scheduled(fixedDelay = 5000)
@GetMapping()
public void sender() {
ExampleObject ex = new ExampleObject();
ex.setDate(new Date());
rabbitTemplate.convertAndSend("q.with.dlx",ex);
}
}
消费
package com.spring.amqp.service;
import java.util.List;
import org.springframework.amqp.AmqpRejectAndDontRequeueException;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;
import com.spring.amqp.domain.ExampleObject;
@Component
public class Consumer {
// Annotation to listen for an ExampleObject
@RabbitListener(queues = "q.with.dlx")
public void handleMessage(ExampleObject exampleObject,
@Header(required = false, name = "x-death") List<String> xDeath) {
System.out.println("Message" + ":" + (xDeath == null ? "" : xDeath));
System.out.println("Received incoming object at " + exampleObject.getDate());
// // String x_header_count = xDeath.get("count");
// System.out.println(x_header_count);
try{
int a = 5 / 0;
System.out.println(a);
}
catch(Exception ex) {
throw new AmqpRejectAndDontRequeueException("amqp exception") ;
}
}
}
**在x-header中我什么都没得到。 ** 现在当我点击localhost:8081 / publish时,它会向q.with.dlx发送一条消息,我正在抛出AmqpRejectAndRequeue异常,然后该消息在“dlq”命名队列中被触发。之后什么也没发生。我有一个名为ExampleObject的域对象,我将其从发布者发送给消费者。
请交叉检查我的所有配置,如果可能,有人可以运行这个,让我知道这是什么错误?提前致谢。
Gary Russell感谢这个令人敬畏的消息传递框架。
答案 0 :(得分:1)
您的TTL位于错误的队列中。
您需要在dlq上配置生存时间:
@Bean
public Queue incomingQueue() {
return new Queue("dlq");
}
添加参数x-message-ttl = 5000
和死信配置,将过期的邮件路由回原始队列。
您的队列bean名称有点令人困惑;你通常会喜欢......
someExchange -> mainQueue (with dead-lettering to DLX)
DLX -> dlq (with TTL and dead-lettering to someExchange)