rabbitMQ使用

一、声明队列交换机绑定关系


import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 声明队列与交换机绑定关系
 *
 */
@Configuration
public class RabbitMQConfigTest {
	
	/**
	 * 测试队列名称
	 */
	public static final String TEST_QUEUE = "test.queue";
	
	/**
	 * 测试交换机名称
	 */
	public static final String TEST_EXCHANGE = "test.exchange";
	
	/**
	 * 测试路由KEY名称
	 */
	public static final String TEST_KEY = "TEST.NONE" ;
	
	/**
	 * 声明队列
	 *
	 * @return org.springframework.amqp.core.Queue
	 */
	@Bean(TEST_QUEUE)
	public Queue testQueue() {
		return new Queue(TEST_QUEUE);
	}

	/**
	 * 声明交换机
	 *
	 * @return org.springframework.amqp.core.Exchange
	 */
	@Bean(TEST_EXCHANGE )
	public TopicExchange emailTodoTopicExchange() {
		return new TopicExchange(TEST_EXCHANGE , true, false);
	}
	
	
	/**
	 * 声明队列与交换机绑定关系
	 *
	 * @param queue    队列
	 * @param exchange 交换机
	 * @return org.springframework.amqp.core.Binding
	 */
	@Bean
	public Binding bindingTestQueue(@Qualifier(TEST_QUEUE) Queue queue,
	                                @Qualifier(TEST_EXCHANGE ) TopicExchange exchange) {
		return BindingBuilder.bind(queue).to(exchange).with(TEST_KEY);
	}
	
	/**
	 * 替代jdk自带转换器
	 *
	 * @return org.springframework.amqp.support.converter.Jackson2JsonMessageConverter
	 */
	@Bean
	public Jackson2JsonMessageConverter testConverter() {
		return new Jackson2JsonMessageConverter();
	}
	
}

二、创建消费者

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.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.io.IOException;

/**
 * 创建消费者
 *
 */

@Component
@Slf4j
public class MqTest {
	
	@Autowired
	private StringRedisTemplate stringRedisTemplate;
	
	/**
	 * 监听追加提取流程结束队列,并发送邮件
	 *
	 * @param event   队列对象
	 * @param channel 信道
	 * @param message 队列信息
	 */
	@RabbitListener(queues = "test.queue")
	public void sendMail(ActivitiEventVO event, Channel channel, Message message) throws IOException {
		// 获取消息体中的幂等性KEY
		String businessKey = event.getBusinessKey();
		// 创造redis缓存KEY,为了记录重试次数
		String key = "TEST_QUEUE" + ":" + businessKey;
		Long count = stringRedisTemplate.opsForValue().increment(key, 1);
		
		try {
			// todo 业务代码 切记出现异常需要抛出,否则不会重试,例如下方注释代码:
			if ("5".equals(businessKey) || "2".equals(businessKey)) {
				log.error("消费失败:{}", businessKey);
				throw new RuntimeException();
			}
		} catch (Exception e) {
			e.printStackTrace();
			// 这里的10次与后续配置文件中的重试次数相同
			if (count != null && count >= 10) {
				log.error("重试次数达限删除");
				// 重试次数超限处理
				basicAck("追加提取流程邮件通知", event, key, channel, message.getMessageProperties().getDeliveryTag());
				return;
			} else {
				throw new RuntimeException();
			}
			
		}
		
		// 正常确认消费消息
		channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
		// 删除redis中缓存的key
		stringRedisTemplate.delete(key);
		log.info("消费成功:{}", businessKey);
	}
	
	/**
	 * 重试次数超限处理
	 *
	 * @param type
	 * @param event
	 * @param key
	 * @param channel
	 * @param var1
	 * @return void
	 */
	public void basicAck(String type, ActivitiEventVO event, String key, Channel channel, long var1) throws IOException {
		try {
			// 删除redis中缓存的key
			stringRedisTemplate.delete(key);
			if ("5".equals(event.getBusinessKey())) {
				log.error("模拟确认失败:{}", event.getBusinessKey());
				throw new RuntimeException();
			}
			// 确认消费消息
			channel.basicAck(var1, false);
			
			// todo 可视业务作出警报处理等,例如发邮件报警

		} catch (Exception e) {
			log.error("消息消费确认失败");
			e.printStackTrace();
			try {
				//出现异常,不删除队列信息,信息重新放置在队列中
				channel.basicNack(var1, false, true);
			} catch (IOException ioException) {
				log.error("重新放置在队列失败");
				ioException.printStackTrace();
			}
		}
	}
}

三、配置yml文件

spring:
  rabbitmq:
    addresses: 172.168.0.1:5672 #RabbitMq的服务器地址
    username: root #RabbitMq的服务器的登录名
    password: root #RabbitMq的服务器的登录密码
    listener:
      simple: 
        retry:
          enabled: true #是否开启消费者重试(为false时关闭消费者重试,这时消费端代码异常会一直重复收到消息)
          max-attempts: 10 #最大重试次数
          initial-interval: 10000 #重试间隔时间(单位毫秒) 
          max-interval: 30000 #重试最大时间间隔(单位毫秒) 
          multiplier: 2 #应用于上一次重试间隔的乘法器,例如上次间隔10秒,本次间隔20秒,但上限不能超过重试最大时间间隔。
        acknowledge-mode: manual #手动确认消息
        prefetch: 1 #消息预读数量 1表示每次从队列中读取一条消息

更正

package com.config;

import cn.hutool.core.collection.CollectionUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.amqp.rabbit.retry.MessageRecoverer;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 声明队列与交换机绑定关系
 *
 * @author 
 * @date 
 */
@Slf4j
@Configuration
public class RabbitMQConfig {
	
	@Autowired
	private MailService mailService;
	
	/**
	 * 队列名称
	 */
	public static final String QUEUE_NAME = "queue.name";
	
	/**
	 * 交换机名称
	 */
	public static final String EXCHANGE_NAME = "exchange.name";
	
	/**
	 * 路由KEY
	 */
	public static final String ROUTING_KEY = routingKey;
	
	/**
	 * 声明交换机
	 *
	 * @return org.springframework.amqp.core.Exchange
	 */
	@Bean(EXCHANGE_NAME)
	public TopicExchange topicExchange() {
		return new TopicExchange(EXCHANGE_NAME, true, false);
	}
	
	/**
	 * 声明队列
	 *
	 * @return org.springframework.amqp.core.Queue
	 */
	@Bean(QUEUE_NAME)
	public Queue addWithdrawEmailEndQueue() {
		return new Queue(QUEUE_NAME);
	}

	
	/**
	 * 声明队列与交换机绑定关系
	 *
	 * @param queue    队列
	 * @param exchange 交换机
	 * @return org.springframework.amqp.core.Binding
	 */
	@Bean
	public Binding bindingAddWithdrawEmailEndQueue(@Qualifier(QUEUE_NAME) Queue queue,
	                                               @Qualifier(EXCHANGE_NAME) TopicExchange exchange) {
		return BindingBuilder.bind(queue).to(exchange).with(ROUTING_KEY);
	}
	
	/**
	 * 替代jdk自带转换器
	 *
	 * @return org.springframework.amqp.support.converter.Jackson2JsonMessageConverter
	 */
	@Bean
	public Jackson2JsonMessageConverter messageConverter() {
		return new Jackson2JsonMessageConverter();
	}
	
	/**
	 * 重试次数超限的自动处理,会自动调用
	 *
	 * @return org.springframework.amqp.rabbit.retry.MessageRecoverer
	 */
	@Bean
	public MessageRecoverer messageRecoverer() {
		return (message, cause) -> {
			// 重试次数超限
			log.info("重试次数超限");
			// todo 业务处理代码
		};
	}
}
spring:
  rabbitmq:
    addresses: 127.0.0.1:5672
    username: guest
    password: guest
    listener:
      simple: 
        retry:
          enabled: true #是否开启消费者重试(为false时关闭消费者重试,这时消费端代码异常会一直重复收到消息)
          max-attempts: 5 #最大重试次数
          initial-interval: 1000 #重试间隔时间(单位毫秒) 
          max-interval: 30000 #重试最大时间间隔(单位毫秒) 
          multiplier: 2 #应用于前一重试间隔的乘法器。
        acknowledge-mode: auto 
        prefetch: 1 #消息预读数量 1表示每次从队列中读取一条消息    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值