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;
}
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);
}
}
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);
}
}
定义延迟队列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";
}