ssm项目整合RabbitMQ实现延时消息

前言

■ 需求

一批XX任务按用户设置的时间开启与结束。

■ 解析

执行时间固定的情况用定时任务足矣,而任务执行时间未知,变化情况的下,就得将定时任务设置成每分钟甚至每秒,不断轮询需要执行的任务。显然,轮询会有性能压力、即时性等问题,这就需要延时队列来解决。在此,我选用RabbitMQ来实现延时队列。

实现方案

在这里插入图片描述

https://help.aliyun.com/document_detail/148083.html

阿里版RabbitMQ实现了原生延时消息方案,不过是收费的。开源版RabbitMQ通过死信队列间接实现延时消息是有缺点的,所以在此通过rabbitmq-delayed-message-exchange插件来实现延迟队列。

实现过程

■ 软件准备

rabbitmq-delayed-message-exchange插件下载

https://www.rabbitmq.com/community-plugins.html

并升级对应版本的 RabbitMQ 和 Erlang
而我选用的是 RabbitMQ 3.8.9、Erlang 23.1

■ 插件安装

将.ez的压缩文件放到rabbitmq安装目录的plugins文件夹里。

执行命令

rabbitmq-plugins enable rabbitmq_delayed_message_exchange

重启mq

■ 代码

1.xml配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:rabbit="http://www.springframework.org/schema/rabbit"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="
       http://www.springframework.org/schema/rabbit
       http://www.springframework.org/schema/rabbit/spring-rabbit.xsd
       http://www.springframework.org/schema/util
       http://www.springframework.org/schema/util/spring-util-4.0.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <description>rabbitmq 连接服务配置</description>
    <!-- 加载配置属性文件 -->
    <context:property-placeholder ignore-unresolvable="true" location="classpath:XXX.properties" />
    <!-- 连接配置 -->
    <rabbit:connection-factory channel-cache-size="10" id="mqConnectionFactory" host="${mq.host}" username="${mq.username}" password="${mq.password}" port="${mq.port}"  virtual-host="${mq.vhost}"/>
    <!--通过指定下面的admin信息,当前producer中的exchange和queue会在rabbitmq服务器上自动生成-->
    <rabbit:admin connection-factory="mqConnectionFactory"/>

    <!-- 声明消息队列 -->
    <!-- durable:是否持久化,宕机恢复后会重持久化日志恢复消息队列 -->
    <!-- exclusive: 仅创建者可以使用的私有队列,断开后自动删除 -->
    <!-- auto_delete: 当所有消费客户端连接断开后,是否自动删除队列 -->
    <!-- 若已经声明消息队列,并且设置跟以下设置不一致,会报错,必须先去管理中心删除该消息队列,再重新创建消息队列 -->
    <rabbit:queue id="taskStartQueue" name="taskStartQueue" durable="true" auto-delete="false" exclusive="false" />
    <rabbit:queue id="taskEndQueue" name="taskEndQueue" durable="true" auto-delete="false" exclusive="false" />

    <util:map id="delayExchangeArgs" map-class="java.util.HashMap">
        <entry key="x-delayed-type" value="direct"/>
    </util:map>

    <!-- 自定义交换机 - 延时交换机 : rabbitMq 第三方插件 rabbitmq_delayed_message_exchange 实现延时队列 -->
    <bean id="taskExchange" name="delayExchange" class="org.springframework.amqp.core.CustomExchange">
        <constructor-arg name="name" value="taskExchange"/>
        <constructor-arg name="type" value="x-delayed-message"/>
        <constructor-arg name="durable" value="true"/>
        <constructor-arg name="autoDelete" value="false"/>
        <constructor-arg name="arguments" ref="delayExchangeArgs"/>
    </bean>

    <util:map id="emptyMap" map-class="java.util.HashMap" />

    <bean id="taskStartBind" class="org.springframework.amqp.core.Binding">
        <constructor-arg name="destination" value="taskStartQueue"/>
        <constructor-arg name="destinationType" value="QUEUE"/>
        <constructor-arg name="exchange" value="taskExchange"/>
        <constructor-arg name="routingKey" value="delay.task.start"/>
        <constructor-arg name="arguments" ref="emptyMap"/>
    </bean>

    <bean id="taskEndBind" class="org.springframework.amqp.core.Binding">
        <constructor-arg name="destination" value="taskEndQueue"/>
        <constructor-arg name="destinationType" value="QUEUE"/>
        <constructor-arg name="exchange" value="taskExchange"/>
        <constructor-arg name="routingKey" value="delay.task.end"/>
        <constructor-arg name="arguments" ref="emptyMap"/>
    </bean>
	
</beans>

2.监听消费

import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.context.annotation.Lazy;
import org.springframework.amqp.core.Message;
import org.springframework.stereotype.Service;

@Service
@Lazy(false)
public class QueueListener {
    
    

    // 开始任务延时队列监听
    @RabbitListener(queues = "taskStartQueue")
    @RabbitHandler
    public void taskStartQueueListener(Message msg){
    
    
        Jackson2JsonMessageConverter jackson2JsonMessageConverter = new Jackson2JsonMessageConverter();
        Task task = (task)jackson2JsonMessageConverter.fromMessage(msg);
        logger.info("==================== 消费延时队列 - 开始任务 ====================\n";
    }

    // 结束任务延时队列监听
    @RabbitListener(queues = "taskEndQueue")
    @RabbitHandler
    public void taskEndQueueListener(Message msg){
    
    
        Jackson2JsonMessageConverter jackson2JsonMessageConverter = new Jackson2JsonMessageConverter();
        Task task = (Task)jackson2JsonMessageConverter.fromMessage(msg);
        logger.info("==================== 消费延时队列 - 结束任务 ====================\n";
    }
}

■ 执行情况

1:30开始任务 - 18:30结束任务
在这里插入图片描述

最后

这样就可通过RabbitMQ实现延时队列功能。

猜你喜欢

转载自blog.csdn.net/qq_24054301/article/details/110440163