rabbitmq可以动态的增减监听队列,目前我想到的使用场景是:
当有消息积压,或者预计不久的将来的某一段时间内,会有大量的消息需要消费时,可以增加监听队列,当恢复平常时候就减少监听队列。
先看消费者工程的配置:
@Configuration
public class MessageListenerConfig {
@Autowired
private CachingConnectionFactory connectionFactory;
@Autowired
private MyAckReceiver myAckReceiver;//消息接收处理类
@Bean
public SimpleMessageListenerContainer simpleMessageListenerContainer() {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory);
container.setConcurrentConsumers(1);
container.setMaxConcurrentConsumers(1);
container.setAcknowledgeMode(AcknowledgeMode.MANUAL); // RabbitMQ默认是自动确认,这里改为手动确认消息
//设置一个队列
container.setQueueNames(FanoutRabbitmqConfig.EMAIL_QUEUE,FanoutRabbitmqConfig.SMS_QUEUE,
RoutingRabbitmqConfig.EMAIL_QUEUE,RoutingRabbitmqConfig.SMS_QUEUE,
TopicsRabbitmqConfig.EMAIL_QUEUE,TopicsRabbitmqConfig.SMS_QUEUE
,DeadLetterConfig.QUEUE_DEAD,DeadLetterConfig.QUEUE_NORMAL);
container.setMessageListener(myAckReceiver);
return container;
}
@Bean
public RabbitAdmin rabbitAdmin(){
return new RabbitAdmin(connectionFactory);
}
}
- SimpleMessageListenerContainer:用来动态设置要监听的队列
- RabbitAdmin:用来设置新增队列与交换机的绑定关系
- MyAckReceiver:消息处理类,实现了ChannelAwareMessageListener接口
MyAckReceiver的实现如下:
@Component
public class MyAckReceiver implements ChannelAwareMessageListener {
@Override
public void onMessage(Message message, Channel channel) throws Exception {
long deliveryTag = message.getMessageProperties().getDeliveryTag();
try {
String consumerQueue = message.getMessageProperties().getConsumerQueue();
String msg = new String(message.getBody());
System.out.println("MyAckReceiver的 "+consumerQueue+" 队列,收到消息 "+msg);
channel.basicAck(deliveryTag, true);
} catch (Exception e) {
channel.basicReject(deliveryTag, false);
e.printStackTrace();
}
}
}
提供动态增减监听队列的接口:
@RestController
public class QueueController {
@Autowired
private SimpleMessageListenerContainer listenerContainer;
@Autowired
private RabbitAdmin rabbitAdmin;
@Resource
private DirectExchange getDirectExchange;
private static final String ROUTING_KEY = "dynamic_queue";
@PostMapping("/queue/{queueName}")
public String addQueue(@PathVariable String queueName){
Queue queue = new Queue(queueName);
rabbitAdmin.declareQueue(queue);
listenerContainer.addQueues(queue);
rabbitAdmin.declareBinding(BindingBuilder.bind(queue).to(getDirectExchange).with(ROUTING_KEY));
return "增加监听队列:"+queueName+" 成功";
}
@DeleteMapping("/queue/{queueName}")
public String deleteQueue(@PathVariable String queueName){
listenerContainer.removeQueueNames(queueName);
// rabbitAdmin.deleteQueue(queueName);
return "移除监听队列:"+queueName+" 成功";
}
}
生产者工程只需要调用相应的接口就可以了,这里使用的是RestTemplate通过http调用,生产实践很大可能是通过feign调用:
@RestController
public class DynamicQueueController {
@Autowired
private RabbitTemplate rabbitTemplate;
private static RestTemplate restTemplate = new RestTemplate();
private static final String ROUTING_KEY = "dynamic_queue";
@GetMapping("/addQueue")
public String addQueue(String queueName){
String url = "http://192.168.231.1:8888/queue/" + queueName;
return restTemplate.postForObject(url,null,String.class);
}
@GetMapping("/push/{msg}")
public String pushMsg(@PathVariable String msg){
rabbitTemplate.convertAndSend(RoutingRabbitmqConfig.EXCHANGE_NAME,ROUTING_KEY,msg);
return "发送成功";
}
@GetMapping("/deleteQueue")
public String deleteQueue(String queueName){
String url = "http://192.168.231.1:8888/queue/" + queueName;
restTemplate.delete(url);
return "删除队列成功";
}
}