Integrating RabbitMQ with Spring Boot: Configuration, Message Production, Consumption, and Reliability

This article explains how to integrate RabbitMQ into a Spring Boot application, covering dependency setup, connection configuration, message sending and receiving, handling complex JSON messages, and ensuring both publishing and consumption reliability through confirmations, callbacks, and QoS settings.

Architect
Architect
Architect
Integrating RabbitMQ with Spring Boot: Configuration, Message Production, Consumption, and Reliability

1. Introduction

Message middleware is commonly used in system development for asynchronous processing, decoupling between systems, and traffic shaping. The following scenarios are considered:

How to integrate with the SpringBoot framework

How to send messages

How to send complex messages

How to guarantee the reliability of sending messages

How to consume messages

How to guarantee the reliability of consuming messages

How to ensure consumer scalability

How to use consumers for traffic shaping

The article uses RabbitMQ as the example message middleware.

2. Integration with SpringBoot

2.1 Add Dependency

Adding the Spring Boot starter for AMQP makes the integration straightforward.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

2.2 Add MQ Service Configuration

spring:
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest
    virtual-host: boot-example

2.3 Inject Message Template

@Autowired
private RabbitTemplate rabbitTemplate;

2.4 Send Message

public void sendMessage() {
    rabbitTemplate.convertAndSend("test", "test", "mq produce send a message");
}

2.5 Consume Message

@Component
@Slf4j
public class MqConsumer {

    @RabbitListener(id = "consumerMessage1", queues = "test")
    public void consumeMessage1(Message message, Channel channel, String content) {
        log.info("receive message1 :{}", content);
    }
}

3. How to Send Complex Messages

When systems exchange complex objects as JSON, a message converter must be configured for serialization and deserialization.

3.1 Producer Sets Message Converter

@Bean
public RabbitTemplate rabbitTemplate(RabbitTemplateConfigurer configurer, ConnectionFactory connectionFactory) {
    RabbitTemplate rabbitTemplate = new RabbitTemplate();
    configurer.configure(rabbitTemplate, connectionFactory);
    rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
    return rabbitTemplate;
}

3.2 Consumer Sets Message Converter

@Bean
public RabbitListenerContainerFactory<?> rabbitListenerContainerFactory(ConnectionFactory connectionFactory) {
    SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
    factory.setConnectionFactory(connectionFactory);
    factory.setMessageConverter(new Jackson2JsonMessageConverter());
    return factory;
}

3.3 Consumer Specifies Listener Container Factory

@RabbitListener(queues = "test3", containerFactory = "rabbitListenerContainerFactory")
public void consumeComplexMessage(Order order) {
    log.info("receive complex message:{}", order);
}

4. Message Sending Reliability

4.1 Why Ensure Sending Reliability

A RabbitMQ node can lose persistent messages if it fails before the messages are written to disk. If the publisher's channel is in confirm mode, the publisher will not receive an ack for the lost message.

Therefore, enabling publisher confirms guarantees that a message is persisted before the broker acknowledges it.

4.2 How to Ensure Sending Reliability

4.2.1 Add Configuration

rabbitmq:
  publisher-confirm-type: correlated
  publisher-returns: true

4.2.2 Specify Callback Functions

Implement RabbitTemplate.ConfirmCallback and RabbitTemplate.ReturnCallback interfaces.

@Configuration
@Slf4j
public class MqConfig implements RabbitTemplate.ConfirmCallback, RabbitTemplate.ReturnCallback {

    /** Message server returns basic.ack */
    @Override
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
        log.info("receive ack confirm:{} from broker server", ack);
    }

    /** Message server returns basic.return */
    @Override
    public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
        log.error("receive return message:{} from broker server,reply code:{},reply text:{},exchange:{},routing key:{}",
                message.toString(), replyCode, replyText, exchange, routingKey);
    }

    @Bean
    public RabbitTemplate rabbitTemplate(RabbitTemplateConfigurer configurer, ConnectionFactory connectionFactory) {
        RabbitTemplate rabbitTemplate = new RabbitTemplate();
        configurer.configure(rabbitTemplate, connectionFactory);
        rabbitTemplate.setReturnCallback(this);
        rabbitTemplate.setConfirmCallback(this);
        rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
        return rabbitTemplate;
    }
}

4.2.3 confirm and returnedMessage

For unroutable messages, the broker first sends basic.return and then basic.ack. Therefore, both callbacks are needed to fully guarantee reliability when routing may fail.

5. Message Consumption Reliability

5.1 Why Ensure Consumption Reliability

When a node delivers a message to a consumer, it must decide whether the message is considered handled. Manual acknowledgements allow the broker to retain the message until the consumer explicitly acknowledges it, preventing loss due to connection or consumer failures.

By using manual acknowledgements, the broker only removes a message after receiving a positive ack.

5.2 How to Ensure Consumption Reliability

Official example with manual ack:

boolean autoAck = false; // set autoAck to false
channel.basicConsume(queueName, autoAck, "a-consumer-tag",
    new DefaultConsumer(channel) {
        @Override
        public void handleDelivery(String consumerTag, Envelope envelope,
                                 AMQP.BasicProperties properties, byte[] body)
                throws IOException {
            long deliveryTag = envelope.getDeliveryTag();
            // negatively acknowledge, the message will be discarded
            channel.basicReject(deliveryTag, false);
        }
    });

In SpringBoot, the default listener mode already provides reliable consumption; the acknowledgement mode can be configured as needed.

6. Ensuring Consumer Scalability

When multiple consumers share a queue, the broker distributes messages in a round‑robin fashion. Adding more consumer instances increases overall consumption capacity, giving the system natural horizontal scalability.

7. Using Consumers for Traffic Shaping

To prevent a consumer from being overwhelmed, set a prefetch count (QoS) so the broker limits the number of unacknowledged messages per channel.

Setting a "prefetch count" defines the maximum number of unacknowledged deliveries permitted on a channel. Once the limit is reached, the broker stops delivering more messages until some are acknowledged.

Thus, basic.qos implements traffic shaping on the consumer side.

8. References

Consumer Acknowledgements and Publisher Confirms

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaRabbitMQReliabilitySpringBoot
Architect
Written by

Architect

Professional architect sharing high‑quality architecture insights. Topics include high‑availability, high‑performance, high‑stability architectures, big data, machine learning, Java, system and distributed architecture, AI, and practical large‑scale architecture case studies. Open to ideas‑driven architects who enjoy sharing and learning.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.