Search code examples
javaspringspring-bootrabbitmqspring-amqp

How do i configure two rabbitlisteners differently in the same project?


I have two queues and they each have messages on them. Queue one has bird objects and queue two has birdspotting object. I'm using a defaultclassmapper to convert the messages back into objects. Is there a way for me to add different configurations on both my rabbitlisteners.

My listeners.

 @Qualifier("bird")
@RabbitListener(queues = "vogels")
public void receiveBird(Bird in)  
    BirdSpotting birdSpotting = new BirdSpotting();
    birdSpotting.setBird(in);
    rabbitTemplate.convertAndSend("vogelspottings",birdSpotting);
}

@Qualifier("birdspotting")
@RabbitListener(queues = "vogelspottingmetlocatie")
public void receiveBirdWithLocation(BirdSpotting birdSpotting){
    service.saveBirdSpotting(birdSpotting);

}

My configuration class.

@Configuration
@EnableRabbit
public class RabbitConf2 implements RabbitListenerConfigurer {
    @Autowired
    DefaultClassMapper mapper;


    @Bean
    public MappingJackson2MessageConverter consumerJackson2MessageConverter() {
        return new MappingJackson2MessageConverter();
    }

    @Bean
    public DefaultMessageHandlerMethodFactory messageHandlerMethodFactory() {
        DefaultMessageHandlerMethodFactory factory = new DefaultMessageHandlerMethodFactory();
        factory.setMessageConverter(consumerJackson2MessageConverter());
        return factory;
    }


    @Override
    public void configureRabbitListeners(RabbitListenerEndpointRegistrar registrar) {
        registrar.setMessageHandlerMethodFactory(messageHandlerMethodFactory());
    }

    @Bean
    public RabbitTemplate rabbitTemplateService2(final ConnectionFactory connectionFactory) {
        final RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        rabbitTemplate.setMessageConverter(producerJackson2MessageConverterService2());
        return rabbitTemplate;
    }

    @Bean
    public Jackson2JsonMessageConverter producerJackson2MessageConverterService2() {
        final Jackson2JsonMessageConverter jackson2JsonMessageConverter = new Jackson2JsonMessageConverter();
        jackson2JsonMessageConverter.setClassMapper(mapper);

        return jackson2JsonMessageConverter;
    }

My two defaultclassmappers for both queues:

@Bean(value = "bird")
    public DefaultClassMapper classMapperService2() {
        DefaultClassMapper classMapper = new DefaultClassMapper();
        Map<String, Class<?>> idClassMapping = new HashMap<>();
        idClassMapping.put("be.kdg.birdgeneratorservice.Bird", Bird.class);
        classMapper.setIdClassMapping(idClassMapping);
        return classMapper;
    }

    @Bean(value = "birdspotting")
    public DefaultClassMapper classMapperService3() {
        DefaultClassMapper classMapper = new DefaultClassMapper();
        Map<String, Class<?>> idClassMapping = new HashMap<>();
        idClassMapping.put("be.kdg.locationservice.BirdSpotting", BirdSpotting.class);
        classMapper.setIdClassMapping(idClassMapping);
        return classMapper;
    }

Solution

  • You need to introduce one more RabbitListenerContainerFactory bean with an appropriate configuration and use its name from the second @RabbitListener:

    /**
     * The bean name of the {@link org.springframework.amqp.rabbit.listener.RabbitListenerContainerFactory}
     * to use to create the message listener container responsible to serve this endpoint.
     * <p>If not specified, the default container factory is used, if any.
     * @return the {@link org.springframework.amqp.rabbit.listener.RabbitListenerContainerFactory}
     * bean name.
     */
    String containerFactory() default "";
    

    This way you will distinguish a default one provided by the Spring Boot and will have your own custom for another use-case.

    See more info in the Docs: https://docs.spring.io/spring-amqp/docs/2.1.4.RELEASE/reference/#async-annotation-driven