Search code examples
rabbitmqspring-rabbit

Spring AMQP - MessageListenerAdapter - pass additional arguments


To create a SimpleMessageListenerContainer, I do something like this.

SimpleMessageConsumer simpleMessageConsumer = new SimpleMessageConsumer();

MessageListenerAdapter adapter =
    new CustomMessageListenerAdapater(simpleMessageConsumer);
adapter.setDefaultListenerMethod("consume");
adapter.setMessageConverter(new SimpleMessageConverter());

SimpleMessageListenerContainer
    container =
    new SimpleMessageListenerContainer(connectionFactory);

container.setMessageListener(adapter);

My SimpleMessageConsumer

  public void consume(String message){
      log.info(message);
}

I noticed in the spring-amqp-refrence that the "annotated listener endpoint infrastructure" allows you to conveniently pass additional Message properties into your consumer like so :

@RabbitListener(queues = "myQueue")
public void processOrder(Order order, @Header("order_type") String orderType) {
...
}

Can that be done using consumer creation approach I mention above? I want to access to some of the headers of the Message object. I know that I can make my consumer implement the MessageListener or the ChannelAwareMessageListener and have access to the entire Message object. However, I dont want the whole Message object, since I like the convenience of using the ContentTypeDelegatingMessageConverter with the Jackson2JsonMessageConverter to do conversion to my desired type(in my real app), before my consumer delegated method is triggered.


Solution

  • You need to use a MessagingMessageConverter with the payloadConverter as the mentioned Jackson2JsonMessageConverter and then in your CustomMessageListenerAdapater you override there a:

    /**
     * Build an array of arguments to be passed into the target listener method. Allows for multiple method arguments to
     * be built from a single message object.
     * <p>
     * The default implementation builds an array with the given message object as sole element. This means that the
     * extracted message will always be passed into a <i>single</i> method argument, even if it is an array, with the
     * target method having a corresponding single argument of the array's type declared.
     * <p>
     * This can be overridden to treat special message content such as arrays differently, for example passing in each
     * element of the message array as distinct method argument.
     * @param extractedMessage the content of the message
     * @return the array of arguments to be passed into the listener method (each element of the array corresponding to
     * a distinct method argument)
     */
    protected Object[] buildListenerArguments(Object extractedMessage) {
    

    casting that extractedMessage to the Message<?> and extract desired headers if that.