自定义Rabbitmq延迟队列注解

1.自定义延迟队列注解

package mis.queue;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Rabbitmq延时队列注解
 * 放在类或方法上
 * 创建延迟队列及消费参考 mis.jobimpl.queue.DelayQueue
 * 发送延迟消息参考 mis.webapp.controller.TestController SendDelayMessage
 * rabbitTemplate.convertAndSend(RabbitmqConfig.DELAY_EXCHANGE,RabbitmqConfig.DELAY_ROUTE_PREFIX+queueName, msg);
 * 消费监听的队列名称为 RabbitmqConfig.DEAD_QUEUE_PREFIX + 注解指定的队列名称
 * 注意延时队列创建后,后面再修改delayTime,需要在rabbitmq上先删掉该队列,否则会报ttl不一致错误
 */
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface RabbitmqDelayQueue {
    /**
     * 延时队列名称
     */
    String value() default "default";

    /**
     * 指定延迟时间,单位秒
     */
    int delayTime() default 60;
}

2.延迟队列扫描类

package mis.queue;

import mis.shared.config.RabbitmqConfig;
import mis.shared.reflection.ServiceBeanContext;
import org.springframework.amqp.core.*;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * 自定义延迟队列扫描并注册
 * 注解RabbitmqDelayQueue
 * 延迟队列定义参考 mis.jobimpl.queue.DelayQueueTest
 * 延迟队列消费参考 mis.jobimpl.queue.DelayQueueTestConsumer
 */
@Component("mqDelayQueueScan")
public class RabbitmqDelayQueueScan implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        try{
            Class clazz = bean.getClass();
            //定义在类上的延迟队列
            RabbitmqDelayQueue delayAnnotation = AnnotationUtils.findAnnotation(clazz, RabbitmqDelayQueue.class);
            if(delayAnnotation != null){
                CreateDelayQueue(delayAnnotation);
            }
            //定义在方法上的延迟队列
            Method[] methods = clazz.getMethods();
            for(Method method:methods){
                delayAnnotation = AnnotationUtils.findAnnotation(method, RabbitmqDelayQueue.class);
                if(delayAnnotation != null){
                    CreateDelayQueue(delayAnnotation);
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return bean;
    }

    //创建延迟队列
    private static void CreateDelayQueue(RabbitmqDelayQueue delayAnnotation) {
        String queueName = delayAnnotation.value();
        int delaySecond = delayAnnotation.delayTime();

        AmqpAdmin amqpAdmin = (AmqpAdmin)ServiceBeanContext.getProvider("amqpAdmin");
        DirectExchange delayExchange = (DirectExchange)ServiceBeanContext.getProvider(RabbitmqConfig.DELAY_EXCHANGE);
        DirectExchange deadExchange = (DirectExchange)ServiceBeanContext.getProvider(RabbitmqConfig.DEAD_EXCHANGE);

        //创建延时队列
        Map args = new HashMap<>(4);
        //当前队列绑定的死信交换机
        args.put("x-dead-letter-exchange", RabbitmqConfig.DEAD_EXCHANGE);
        //当前队列的死信路由key
        args.put("x-dead-letter-routing-key", RabbitmqConfig.DEAD_ROUTE_PREFIX+queueName);
        //队列的TTL
        args.put("x-message-ttl", delaySecond * 1000);
        //延迟队列
        Queue delayQueue = QueueBuilder.durable(RabbitmqConfig.DELAY_QUEUE_PREFIX + queueName)
                .withArguments(args).build();
        amqpAdmin.declareQueue(delayQueue);
        //延迟交换机绑定延迟队列
        Binding delayBind = BindingBuilder.bind(delayQueue).to(delayExchange).with(RabbitmqConfig.DELAY_ROUTE_PREFIX + queueName);
        amqpAdmin.declareBinding(delayBind);

        //死信队列
        Queue deadQueue = new Queue(RabbitmqConfig.DEAD_QUEUE_PREFIX + queueName);
        amqpAdmin.declareQueue(deadQueue);
        Binding deadBind = BindingBuilder.bind(deadQueue).to(deadExchange).with(RabbitmqConfig.DEAD_ROUTE_PREFIX+queueName);
        amqpAdmin.declareBinding(deadBind);
    }

}

 3.延迟队列和死信队列交换机

package mis.queue;

import mis.shared.config.RabbitmqConfig;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * Rabbitmq 延迟队列公用交换机
 */
@Configuration
public class RabbitmqExchange {
    //创建延时Exchange
    @Bean(RabbitmqConfig.DELAY_EXCHANGE)
    public DirectExchange DelayExchange() {
        return new DirectExchange(RabbitmqConfig.DELAY_EXCHANGE);
    }

    //创建死信Exchange
    @Bean(RabbitmqConfig.DEAD_EXCHANGE)
    public DirectExchange DeadLetterExchange() {
        return new DirectExchange(RabbitmqConfig.DEAD_EXCHANGE);
    }
}

4.延迟队列注解使用

        定义延迟队列delayTest,延迟时间为10秒,并监听延迟消息。  

package mis.jobimpl.queue;

import com.rabbitmq.client.Channel;
import mis.queue.RabbitmqDelayQueue;
import mis.shared.config.RabbitmqConfig;
import mis.shared.date.DateUnitl;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.Date;

/**
 * 延迟队列消费者,监听的队列名称为
 * RabbitmqConfig.DEAD_QUEUE_PREFIX + 注解指定的延迟队列名称
 * 发送延时消息参考 mis.webapp.controller.TestController#SendDelayMessage
 */
@Component
@RabbitmqDelayQueue(value = "delayTest",delayTime = 10)
public class DelayQueueTest {

    @RabbitListener(queues = RabbitmqConfig.DEAD_QUEUE_PREFIX + "delayTest")
    public void receive(Message message, Channel channel) throws IOException {
        String msg = new String(message.getBody());
        System.out.println("当前时间:" + DateUnitl.GetStrDate(new Date(), "yyyy-MM-dd HH:mm:ss") + ",死信队列delayTest收到消息:" + msg);
    }

}

        往延迟队列中发送消息。 

    @PostMapping(value = "/sendDelayMessage")
    public String SendDelayMessage(@RequestParam("msg") String msg,@RequestParam("queueName") String queueName) {
        //queueName为@RabbitmqDelayQueue指定的队列名称
        System.out.println("发送延时消息,message:"+msg+", type:"+queueName+",当前时间:"+ DateUnitl.GetStrDate(new Date(),"yyyy-MM-dd HH:mm:ss"));
        rabbitTemplate.convertAndSend(RabbitmqConfig.DELAY_EXCHANGE,RabbitmqConfig.DELAY_ROUTE_PREFIX+queueName, msg);
        return "ok";
    }

 

你可能感兴趣的:(java,rabbitmq)