导入依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
配置application.yml文件
spring:
jackson:
date-format: yyyy-MM-dd
time-zone: GMT+8
rabbitmq:
host: 192.168.31.14
port: 5672
username: hello
password: 123456
virtual-host: /myhost
listener:
simple:
acknowledge-mode: manual # 消费者手动签收消息
prefetch: 10 #表示消费者一次从队列中处理10条数 (100-->10次)
#消息发送到交换机确认机制,是否确认回调
#如果没有本条配置信息,当消费者收到生产者发送的消息后,生产者无法收到确认成功的回调信息
publisher-confirm-type: correlated
写配置类
@Configuration
public class RabbitMQConfig {
RabbitTemplate.ReturnCallback returnCallback = new RabbitTemplate.ReturnCallback() {
@Override
public void returnedMessage(Message message, int i, String s, String s1, String s2) {
System.out.println("返回的错误编码:"+i);
System.out.println("返回的消息:"+s);
System.out.println("交换机:"+s1);
System.out.println("路由key:"+s2);
}
};
RabbitTemplate.ConfirmCallback confirmCallback = new RabbitTemplate.ConfirmCallback() {
@Override
public void confirm(CorrelationData correlationData, boolean b, String s) {
if(b){
System.out.println("交换机成功收到消息");
}
if(!b){
System.out.println("拒收的原因:"+s);
}
}
};
@Bean//配置模板对象
public RabbitTemplate rabbitTemplate(ConnectionFactory factory){
RabbitTemplate template = new RabbitTemplate();
//配置消息转换器
template.setMessageConverter(messageConverter());
//配置连接工厂
template.setConnectionFactory(factory);
//配置队列监听
template.setReturnCallback(returnCallback);
//配置交换机监听
template.setConfirmCallback(confirmCallback);
//消息强制退回
template.setMandatory(true);
return template;
}
//配置队列消息发送格式
public Jackson2JsonMessageConverter messageConverter(){
return new Jackson2JsonMessageConverter();
}
@Bean//配置队列超时发送至死信交换机
public Queue payOrderQueue(){
//配置参数
Map args = new HashMap<>();
args.put("x-dead-letter-exchange","pay_order_dead_exchange");
//配置路由key
args.put("x-dead-letter-routing-key","pay.order.dead");
//配置死亡时间30秒
args.put("x-message-ttl",30000);
return new Queue("pay_order_queue",true,false,false,args);
}
@Bean//配置交换机
public TopicExchange payOrderExchange(){
return new TopicExchange("pay_order_exchange");
}
@Bean//绑定交换机和队列
public Binding bindPayOrderQueue(){
return BindingBuilder.bind(payOrderQueue()).to(payOrderExchange()).with("pay.#");
}
@Bean//配置死信交换机
public TopicExchange payOrderDeadExchange(){
return new TopicExchange("pay_order_dead_exchange");
}
@Bean//配置死信队列
public Queue payOrderDeadQueue(){
return new Queue("pay_order_dead_queue",true,false,false);
}
@Bean//绑定死信队列和死信交换机并设置路由key
public Binding bindPayOrderDeadQueue(){
return BindingBuilder.bind(payOrderDeadQueue()).to(payOrderDeadExchange()).with("pay.order.dead");
}
}
测试代码
@Component
public class StaticScheduler {
@Autowired
private RabbitTemplate rabbitTemplate;
//运行项目后,会每隔3秒向交换机发送一条信息
@Scheduled(cron = "0/3 * * * * ?")
public void doStatic(){
Map map = new HashMap<>();
map.put("id", 1001);
map.put("orderNo", "testno");
rabbitTemplate.convertAndSend("pay_order_exchange", "pay." + map.get("orderNo"), map);
}
}
消费者
//该方法负责处理哪个队列中的数据
@RabbitListener(queues = "pay_order_dead_queue")
@RabbitHandler //告诉RabbitMQ这是一个用来处理消息的方法
//@Payload注解的含义就是:rabbitmq会将消息队列中的数据,传递给该注解所标记的参数。
public void processMsg(@Payload Map map, Channel channel, @Headers Map headers){
System.out.println("消费者受到的消息:"+map.get("orderNo"));
Long id = (Long)headers.get(AmqpHeaders.DELIVERY_TAG);
try {
channel.basicAck(id,false);
} catch (IOException e) {
e.printStackTrace();
}
}
注:springboot初始化时会扫描配置类的注解@Configuration,会将里面的带有@Bean注解的方法运行得到我们配置的对象将其放入Spring容器,替代之前的Spring配置文件。这里我们配置的连接工厂、消息转换器、监听器等被注入到rabbitmq模板中,再将模板对象注入业务类中直接使用。通模板对象我们发送一条消息,先被消息转换器转换成我们设定的json字符串,然后发送至指定的交换机,通过路由key再从交换机发送至队列,如果未到达交换机会被返回,监听交换机的方法会内执行,如果路由key无法匹配,同样会被退回,会被监听队列的RabbitTemplate.ReturnCallback监听,执行其中的方法,到达队列后如果30秒未被消费掉,则会被发送到死信交换机,然后匹配至路由key符合条件的队列,等待被消费,如不匹配则会被丢掉。