Search code examples
javarabbitmqspring-integrationamqpspring-amqp

Easiest way to construct @RabbitListener at runtime


What would be the easiest way to construct this at runtime?

@RabbitListener(bindings = @QueueBinding(
    value = @Queue(value = "providedAtRuntime", durable = "true"),
    exchange = @Exchange(value = "providedAtRuntime", ignoreDeclarationExceptions = "true"),
    key = "providedAtRuntime"), containerFactory = "cFac")
public class RabbitProcessor {
    @RabbitHandler
    public void receive (String smth){
        System.out.println(smth);
    }
}

I would like to define the listener, but provide exchange, queue name and binding at runtime. Also this listener should not start automatically, but when called by start() method. At same time it should auto-declare bindings and queues etc. When called stop(), it should just stop consuming.


Solution

  • I think it's not possible with annotations, but you can create a custom SimpleMessageListenerContainer.

    here is a simple solution:

    public static AbstractMessageListenerContainer startListening(RabbitAdmin rabbitAdmin, Queue queue, Exchange exchange, String key, MessageListener messageListener) {
        rabbitAdmin.declareBinding(BindingBuilder.bind(queue).to(exchange).with(key).noargs());
        SimpleMessageListenerContainer listener = new SimpleMessageListenerContainer(rabbitAdmin.getRabbitTemplate().getConnectionFactory());
        listener.addQueues(queue);
        listener.setMessageListener(messageListener);
        listener.start();
    
        return listener;
    }
    

    and you can call it as:

    ConfigurableApplicationContext ctx = SpringApplication.run(DemoApplication.class, args);
    
     ConnectionFactory connectionFactory = ctx.getBean(ConnectionFactory.class);
     RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
     AbstractMessageListenerContainer container = startListening(rabbitAdmin, rabbitAdmin.declareQueue(),
             new DirectExchange("amq.direct"), "testRoute", message -> {
                 System.out.println(new String(message.getBody()));
             });
    

    And you can

    AbstractMessageListenerContainer.destroy() or AbstractMessageListenerContainer.stop() it.

    Tested with spring boot 1.5.8.RELEASE and RabbitMQ 3.6.10