Skip to main content
Advertisement

13.2 Message Queue Fundamentals and RabbitMQ Integration

A Message Queue (MQ) is middleware enabling asynchronous communication between services. Instead of Service A waiting for Service B's response, it places a message in the queue and moves on — Service B consumes it at its own pace. This dramatically reduces inter-service coupling.

1. AMQP and Exchange-Queue Routing Concepts

RabbitMQ operates on the AMQP protocol. Messages always flow in this order: Producer → Exchange → Binding → Queue → Consumer.

  • Exchange Types:
    • Direct: Routes to queues where the routing key matches exactly (1:1)
    • Topic: Routes to multiple queues using wildcard (*, #) pattern matching
    • Fanout: Broadcasts to all bound queues (1:N)

2. Quick Spring AMQP Setup

implementation 'org.springframework.boot:spring-boot-starter-amqp'
@Configuration
public class RabbitMqConfig {

public static final String QUEUE_NAME = "order.queue";
public static final String EXCHANGE_NAME = "order.exchange";
public static final String ROUTING_KEY = "order.created";

@Bean
public Queue orderQueue() {
return new Queue(QUEUE_NAME, true); // durable=true: survives broker restarts
}

@Bean
public DirectExchange orderExchange() {
return new DirectExchange(EXCHANGE_NAME);
}

@Bean
public Binding binding(Queue orderQueue, DirectExchange orderExchange) {
return BindingBuilder.bind(orderQueue).to(orderExchange).with(ROUTING_KEY);
}

@Bean
public MessageConverter jsonMessageConverter() {
return new Jackson2JsonMessageConverter(); // Serializes Java objects to JSON
}
}

3. Publishing (Producer) and Consuming (Consumer)

// [Producer] Publishing a message
@Service
@RequiredArgsConstructor
public class OrderProducer {
private final RabbitTemplate rabbitTemplate;

public void sendOrderCreatedEvent(OrderCreatedEvent event) {
rabbitTemplate.convertAndSend(
RabbitMqConfig.EXCHANGE_NAME,
RabbitMqConfig.ROUTING_KEY,
event
);
log.info("Order event published: {}", event.getOrderId());
}
}

// [Consumer] Consuming from the queue
@Service
public class OrderConsumer {

@RabbitListener(queues = RabbitMqConfig.QUEUE_NAME)
public void handleOrderCreated(OrderCreatedEvent event) {
log.info("Received order event: {}", event.getOrderId());
// Async post-processing: send email, deduct inventory, etc.
}
}
warning

If an exception is thrown inside @RabbitListener, RabbitMQ will by default requeue the message — causing an infinite retry loop. Always configure a Dead Letter Queue (DLQ) or a RetryInterceptor with a maximum retry count to prevent this.

Advertisement