实现Direct,Fanout,Topic和死信转发方式实现的延迟队列
一个让处女座程序员很难受的问题:
每次申明一个队列,都需要用@Bean注解在config类里面显式的往容器里面注入一个Queue Bean和Binding Bean,十几个队列下来,那场面简直不能忍.
怎么解决呢,思路:
通过遍历枚举的方式,统一往spring容器中注入bean.废话不多说,上代码
一 使用场景说明
1.Direct
根据routekey精确匹配消费,只消费一次
2.Fanout
广播消息队列,同交换机内的所有消费者,都接收到消息
3.Topic
支持模糊匹配,可匹配到多个.配合AnonymousQueue队列可实现集群内多点同一业务集群消费.如:修改集群内所有应用内存中配置
4.TTL
延迟队列,实现消息延迟指定时间消费
二 关键代码
- 配置类:
import com.google.common.collect.Maps;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @author onlinever
* @date 2018/09/06
*/
@Service
public class RabbitQueueBeanRegister implements BeanDefinitionRegistryPostProcessor, ApplicationContextAware {
private ApplicationContext applicationContext;
private BeanDefinitionRegistry beanDefinitionRegistry;
private String adapterSuffix = "Adapter";
private Map<RabbitQueueEnum, Queue> topicQueues = Maps.newHashMap();
private List<TopicConsumer> topicConsumers;
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
this.beanDefinitionRegistry = beanDefinitionRegistry;
//声明交换机
declareExchange();
//声明队列和绑定
declareQueueAndBinding();
//奇怪的执行顺序
if (haveTopicQueue()) {
declareTopicMessageListenerAdapter();
declareTopicMessageListenerContainer();
}
}
private boolean haveTopicQueue() {
try {
topicConsumers = new ArrayList<>(applicationContext.getBeansOfType(TopicConsumer.class).values());
return !topicConsumers.isEmpty();
} catch (Exception e) {
System.out.println(e.getMessage());
return false;
}
}
/**
* 声明交换机
*/
private void declareExchange() {
for (RabbitExchangeEnum rabbitExchangeEnum : RabbitExchangeEnum.