rabbitmq + Spring boot 整合-延迟消费 在【队列上】(05)

目录
rabbitmq-直接交换模式
rabbitmq-广播模式- 路由
rabbitmq-广播模式- 交换机
rabbitmq-转发模式
rabbitmq-延迟消费 在【队列上】
rabbitmq-延迟消费 在【消息上】

源码地址:https://gitee.com/caiwang/rabbitmq-project

在介绍具体的实现思路之前,我们先来介绍一下RabbitMQ的两个特性,
一个是Time-To-Live Extensions,另一个是Dead Letter Exchanges

Time-To-Live Extensions RabbitMQ允许我们为消息或者队列设置TTL(time to live),也就是过期时间 TTL表明了一条消息可在队列中存活的最大时间,单位为毫秒 也就是说,当某条消息被设置了TTL或者当某条消息进入了设置了TTL的队列时,这条消息会在经过TTL秒后“死亡”,成为Dead Letter 如果既配置了消息的TTL,又配置了队列的TTL,那么较小的那个值会被取用

Dead Letter Exchange 在RabbitMQ中,一共有三种消息的“死亡”形式 消息被拒绝。通过调用basic.reject或者basic.nack并且设置的requeue参数为false。也就是:requeue=false 消息因为设置了TTL而过期。 消息进入了一条已经达到最大长度的队列 如果队列设置了Dead Letter Exchange(DLX),那么这些Dead Letter就会被重新publish到Dead Letter Exchange 通过Dead Letter Exchange路由到其他队列


为了方便接下来的测试,我们将delay_queue_per_message_ttl以及delay_queue_per_queue_ttl的DLX配置分两个目录进行演示,
且过期的消息都会通过DLX转发到delay_process_queue


在 commom中创建

DelaySenderEessageCommon

public class DelaySenderEessageCommon {

	/**
	 * ========= delay_queue_per_message_ttl:TTL配置在【消息上】的缓冲队列。===========
	 */
	/**
	 * TTL配置在【消息上】的缓冲队列
	 */
	public static final String DELAY_EXCHANGE_QUEUE_TTL_NAME = "delay_exchange_queue_ttl_name";

	/**
	 * TTL配置在【队列上】的缓冲队列
	 */
	public static final String DELAY_EXCHANGE_SLOW_NAME = "delay_exchange_slow_name";
	/**
	 * 【消息上】 实际消费队列
	 */
	public static final String DELAY_EXCHANGE_QUEUE_NAME = "delay_exchange_queue_name";


}

在项目【rabbitmq-sender-project05】中创建

DelaySenderEessageConfig

@Configuration
public class DelaySenderEessageConfig {


	/**
	 * 功能描述  delay_queue_per_message_ttl TTL配置在【消息上】的缓冲队列
	 * @param
	 * @return org.springframework.amqp.core.Queue
	 * @author cailu
	 * @date 2020/3/30 17:11
	 */
	@Bean
	public Queue delayQueuePerMessageTTL() {

		return QueueBuilder.durable(DelaySenderEessageCommon.DELAY_EXCHANGE_QUEUE_TTL_NAME)

				//x-dead-letter-exchange	声明了队列里的死信转发到的DLX名称,
				//x-dead-letter-routing-key 声明了这些死信在转发时携带的DLK名称

				// DLX,dead letter发送到的exchange 延迟交换名称
				.withArgument("x-dead-letter-exchange", DelaySenderEessageCommon.DELAY_EXCHANGE_SLOW_NAME)
				// DLK dead letter携带的routing key 每个消息的延迟队列名称
				.withArgument("x-dead-letter-routing-key", DelaySenderEessageCommon.DELAY_EXCHANGE_QUEUE_NAME)
				.build();
	}


	/**
	 * 功能描述  首先,我们需要配置DLX
	 * @param
	 * @return org.springframework.amqp.core.DirectExchange
	 * @author cailu
	 * @date 2020/3/30 17:23
	 */
	@Bean
	DirectExchange delayExchange() {
		return new DirectExchange(DelaySenderEessageCommon.DELAY_EXCHANGE_SLOW_NAME);
	}

	/**
	 * 功能描述 delay_process_queue:实际消费队列
	 * @param
	 * @return org.springframework.amqp.core.Queue
	 * @author cailu
	 * @date 2020/3/30 17:22
	 */
	@Bean
	Queue delayProcessQueue() {
		return QueueBuilder.durable(DelaySenderEessageCommon.DELAY_EXCHANGE_QUEUE_NAME)
				.build();
	}


	/**
	 * 功能描述 然后再将该DLX绑定到实际消费队列即delay_process_queue上。
	 * 这样所有的死信都会通过DLX被转发到delay_process_queue:
	 * @param delayProcessQueue 延迟处理队列
	 * @param delayExchange     延迟交换
	 * @return org.springframework.amqp.core.Binding
	 * @author cailu
	 * @date 2020/3/30 17:23
	 */
	@Bean
	Binding dlxBinding(Queue delayProcessQueue, DirectExchange delayExchange) {
		return BindingBuilder.bind(delayProcessQueue)
				.to(delayExchange)
				.with(DelaySenderEessageCommon.DELAY_EXCHANGE_QUEUE_NAME);
	}
}

创建[延迟消费 设置消息的TTL属性]

ExpirationMessagePostProcessor

public class ExpirationMessagePostProcessor implements MessagePostProcessor {

	// 毫秒
	private final Long ttl;

	public ExpirationMessagePostProcessor(Long ttl) {
		this.ttl = ttl;
	}


	@Override
	public Message postProcessMessage(Message message) throws AmqpException {
		message.getMessageProperties()
				// 设置per-message的失效时间
				.setExpiration(ttl.toString());
		return message;
	}
}

创建消息模板

DelaySenderEessageTemplate:

@Component
public class DelaySenderEessageTemplate {

	private Logger logger = (Logger) LoggerFactory.getLogger(this.getClass());

	@Autowired
	private RabbitTemplate rabbitTemplate;


	/**
	 * 功能描述 配置在消息上的延迟消费
	 * 在发布消息时 一定要注意 发布的消息 是在【延迟队列】中的【缓冲队列】里
	 * 通过TTL的绑定 使其在 死信队列 中 按照时间 自动消化掉
	 * @return void
	 * @author cailu
	 * @date 2020/3/31 11:19
	 */
	public void delayQueuePerMessageTTL() {
		//延迟的时间 毫秒
		long expiration = 30000;
		rabbitTemplate.convertAndSend(DelaySenderEessageCommon.DELAY_EXCHANGE_QUEUE_TTL_NAME,
				(Object) ("Message From delay_exchange_queue_ttl_name with expiration " + expiration),
				new ExpirationMessagePostProcessor(expiration));
	}


}

现在我们启动项目:观察mq后台
在这里插入图片描述

在这里插入图片描述

我们发送一条信息
可以看到 首先 我们发送的信息在delay_exchange_queue_ttl_name 中,等待单位时间内(也就是需要延迟的时间),那么这条消息就会自动转发到delay_exchange_queue_name中

在这里插入图片描述

这里的转发时间是由ExpirationMessagePostProcessor类中ExpirationMessagePostProcessor管理的,
可以自定义时间,我这里方便演示,直接在代码中定义了,后期跟进业务,可以更改为动态传入

现在已经做了延迟了,也就是说 我们真正的消费队列 是:delay_exchange_queue_name,
而delay_exchange_queue_ttl_name 只是临时的,或者说是我们在单位时间内被定义出来的,
其实这里有很多中用法,具体用法可以根据具体业务而定,这里只做展示


接下来 我们来创建消费者
在项目【rabbitmq-receiver-project05】中创建

DelaySenderEessageReceiver:

@Component
public class DelaySenderEessageReceiver {

	/**
	 * 功能描述  监听 在【消息上】 延迟消费
	 * @param str 内容
	 * @return void
	 * @author cailu
	 * @date 2020/3/31 15:14
	 */
	@RabbitListener(queues = DelaySenderEessageCommon.DELAY_EXCHANGE_QUEUE_NAME)
	public void processQueue(String str) {
		System.out.println("Receive---delay_exchange_queue_name:========================:" + str.toString());
	}


}

启动消费者 观察日志

在这里插入图片描述

可以看到刚才的延迟的两条 全部被消费掉


至此 rabbitmq-延迟消费 在【队列上】完毕

源码地址:https://gitee.com/caiwang/rabbitmq-project

下一篇:rabbitmq-延迟消费 在【消息上】

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值