Spring Boot + RabbitMQ – Decoupling Microservices Communication

RabbitMQ is an open-source message broker software that implements the Advanced Message Queuing Protocol (AMQP). It serves as a messaging intermediary between different components of an application, facilitating communication by enabling the exchange of messages across various systems and languages.

Key concepts and components of RabbitMQ include:

1. Message Broker:

RabbitMQ acts as a message broker, receiving, storing, and routing messages from producers to consumers. It ensures reliable message delivery by managing queues and exchanges.

2. Exchanges:

Exchanges receive messages from producers and route them to queues. Different types of exchanges (e.g., direct, topic, fanout, headers) determine the routing behavior based on message attributes.

3. Queues:

Queues store messages until they are consumed by subscribers. Consumers retrieve and process messages from queues.

4. Routing Keys:

Messages are published to exchanges with a routing key. Exchanges use this routing key to determine how to route the message to the appropriate queue(s).

5. Bindings:

Bindings link exchanges to queues, specifying the routing rules based on routing keys or patterns.

6. Virtual Hosts:

RabbitMQ allows multiple virtual hosts, enabling isolation between different applications or environments.

7. Publishers (Producers) and Subscribers (Consumers):

Publishers produce messages and send them to RabbitMQ, while subscribers consume messages from RabbitMQ.

Spring Boot offers seamless integration with RabbitMQ. One of the main use case of RabbitMQ is decoupling microservices communication. RabbitMQ can facilitate communication between loosely coupled services in a microservices architecture. It helps by reducing direct dependencies among services, allowing them to communicate through message exchanges. To see a demo of this we will create the following three services. Once the order is received in Order service the other two services will be notified for Fulfilment and Payment.

i) Order Service

ii)Fulfilment Service

iii) Payment Service

To use RabbitMQ with Spring Boot add the below dependency

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

Then configure RabbitMQ properties

spring.rabbitmq.host = localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest

Order Service:

Define an API for placing the order. Once the order is received , save the order to DB and create a RabbitMQ producer to notify Fulfilment and Payment service using Fanout Exchange.

Fanout Exchanges broadcast messages to all the queues that are bound to them. They don’t use routing keys for message delivery. Messages sent to a fanout exchange will be delivered to all the queues that are bound to that exchange. It’s a simple broadcasting mechanism, where every queue bound to the exchange receives a copy of the message.


Order Service:

@Service
public class OrderService {

	@Autowired
	RabbitTemplate template;
	
	public ResponseEntity<OrderResponse> placeOrder(OrderRequest request) throws JsonProcessingException{		
		//Add logic to save the order to DB		
		//Notify downward systems for fulfilment and payment
		template.convertAndSend("x.order-notification","",request);		
		OrderResponse resp = new OrderResponse();
		resp.setMessage("Order Created");
		resp.setStatus(201);
		return new ResponseEntity<OrderResponse>(resp, HttpStatusCode.valueOf(201));
	}
}

RabbitMQ Configuration: Creating Queues, fanout Exchange and binding queue to exchange

@Configuration
public class RabbitMQConfig {

	@Bean
	public Declarables createOrderNotificationSchema() {

		FanoutExchange fanoutExchange = new FanoutExchange("x.order-notification");
		Queue fulfilment = new Queue("q.order-fulfilment");
		Queue payment = new Queue("q.order-payment");
		return new Declarables(fanoutExchange, 
				fulfilment,
				payment,
				BindingBuilder.bind(payment).to(fanoutExchange),
				BindingBuilder.bind(fulfilment).to(fanoutExchange)
				);

	}

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

	@Bean
	public MessageConverter messageConverter() {
		return new Jackson2JsonMessageConverter();
	}
}

Jackson2JsonMessageConverter is one of the message converters provided by Spring AMQP, and it uses the Jackson library for JSON processing. It enables to convert Java objects to JSON format before sending them as messages to RabbitMQ and convert JSON messages received from RabbitMQ back into Java objects.

Let’s post the order and see the message in the queues.

Fulfilment Service – RabbitMQ Consumer:

@Component
@Slf4j
public class FulfilmentService {
    @RabbitListener(queues = "q.order-fulfilment")
    public void fulFilOrder(OrderRequest message) {    	
        log.info("Order Fulfilment :"+ message.getProductName());
        //Add Logic for order fulfilment
    }
}

Payment Service – RabbitMQ Consumer:

@Component
@Slf4j
public class PaymentService {
    @RabbitListener(queues = "q.order-fulfilment")
    public void payment(OrderRequest message) {    	
        log.info("Order Payment :"+ message.getProductName());
        //Add Logic for order payment
    }

}

For complete source code: https://github.com/MMahendravarman/Springboot_Examples

Leave a Reply

Your email address will not be published. Required fields are marked *