Home > database >  How to process messages from Spring Boot @RabbitListener in different handlers?
How to process messages from Spring Boot @RabbitListener in different handlers?

Time:08-04

I'm trying to use request/response pattern for Spring Boot using AMQP and Spring-web. I have client service that has @RestController and AsyncRabbit configuration with Direct Exchange, Routing key etc. and server that has simple listener for request queue.
Client (something like rest gateway controller):

@RestController
public class ClientController {
    @GetMapping("/test1")
    public String getRequest() {
       ListenableFuture<String> listenableFuture = asyncRabbitTemplate.convertAndReceiveAsType(
           directExchange.getName(),
           routingKey,
           testDto,
           new ParameterizedTypeReference<>() {}
       );

       return listenableFuture.get(); // Here I receive response from server services
    }

    @GetMapping("/test2")
    public String getRequest2() {
       ListenableFuture<String> listenableFuture = asyncRabbitTemplate.convertAndReceiveAsType(
           /* Same properties but I use another DTO object for request */
       );

       return listenableFuture.get()
}

Server:

@RabbitListener(queues = "#{queue.name}", concurrency = "10")
@Component
public class Consumer {
    @RabbitHandler
    public String receive(TestDto testDto) {
        ...
    }

    @RabbitHandler
    public String receive2(AnotherTestDto anotherTestDto) {
        ...
    }
}

How should I implement Rabbit listener to process each REST request?
I found only two ways to do that:

  1. Using @RabbitHandler as in the example above. But for each request method (GET, POST, etc.) I need unique DTO class to send message and process it in correct handler even if "request body" is almost same (number of request methods = number of DTO class to send). I'm not sure that is right way.
  2. Leave one Consumer and call desired method to process that depends on message body (trivial if-else):
...
@RabbitListener(queues = "#{queue.name}")
public String receive(MessageDto messageDto) {
    if (messageDto.requestType == "get.method1") {
        return serverService.processThat(messageDto);
    } else if (messageDto.requestType == "post.method2") {
        return serverService.processAnother(messageDto);
    } else if ...
    ...
}
...

But add new if-else branch every time is not very convenient so I really out of ideas.

CodePudding user response:

You may consider to use different queues for different request types. All of them are going to be bound to the same direct exchange, but with their respective routing key.

What you would need on the consumer side is just to add a new @RabbitListener for respective queue. And bind that queue to the exchange with its routing key.

That's actually a beauty of the AMQP protol by itself: the producer always publish to the same exchange with respective routing key. The consumer registers its interest for routing keys and binds a queue. The rest of routing logic is done on the AMQP broker.

See more info in docs: https://www.rabbitmq.com/tutorials/tutorial-four-spring-amqp.html

  • Related