3

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.

Bojan Vukasovic
  • 2,054
  • 22
  • 43
  • this? https://stackoverflow.com/questions/14268981/modify-a-class-definitions-annotation-string-parameter-at-runtime – Eugene Nov 16 '17 at 13:56

1 Answers1

7

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

zur4ik
  • 6,072
  • 9
  • 52
  • 78
Nonika
  • 2,490
  • 13
  • 15
  • Thanks. I knew about this approach. I just wanted to check if there is something even easier than this - without using rabbitAdmin directly. – Bojan Vukasovic Nov 16 '17 at 14:38
  • 1
    No, there is nothing because it's just impossible or won't be efficient. – Artem Bilan Nov 16 '17 at 14:56
  • @Artem Bilan - is there guarantee that queues, exchanges and bindings will be redeclared on connection lost? also will listener container reconnect automatically? – Bojan Vukasovic Nov 16 '17 at 22:43
  • It is done if everything are beans in the application context and `RabbitAdmin` really takes care about recreation entities on connection reconnect. See this JIRA for more info: https://jira.spring.io/browse/AMQP-758 – Artem Bilan Nov 16 '17 at 22:51
  • here is an old link from spring forum. it may be helpful. http://forum.spring.io/forum/spring-projects/integration/amqp/97129-automatic-reconnects – Nonika Nov 17 '17 at 06:56