In questo articolo vedrai come implementare un’architettura a microservizi impiegando RabbitMQ in applicazioni Spring Boot per lo scambio di messaggi.
Architettura a microservizi? RabbitMQ? Non farti spaventare dai nomi, tra poco ti spiegherò di cosa stiamo parlando.
Se sei capitato qui, sarai interessato al concetto di microservizi. Sul web troverai già molti articoli sulla definizione di microservizi e sui vantaggi che questa architettura comporta, per cui in questo articolo ne parlerò solo brevemente. Quello che invece voglio farti vedere, è un modo pratico per applicare il concetto di microservizi su applicazioni Spring.
Concetto di microservizi
Un’applicazione può essere suddivisa nelle sue funzioni in più servizi. Un micro-servizio è quindi una funzione dell’applicazione che garantisce il suo funzionamento indipendentemente dalle altre, portando ad una alta scalabilità. Inoltre, ogni micro-servizio è progettato per eseguire esclusivamente la sua funzione, risultando in un’applicazione di modeste dimensioni e ben strutturata.
RabbitMQ
RabbitMQ non è altro che un “broker di messaggi” che implementa il protocollo AMQP. Funziona come un programma intermedio che permette lo scambio di messaggi tra altre applicazioni, preoccupandosi della convalida, della trasformazione e dello smistamento, utilizzando code.
Ottenere RabbitMQ
Per utilizzare RabbitMQ occorre scaricare e installare RabbitMQ Server, tramite uno dei modi proposti dal sito, ad esempio Homebrew (Mac) piuttosto che tramite l’immagine Docker.
Per l’esempio di questo articolo ho utilizzato Homebrew per l’istallazione, dopo di che ho ho avviato RabbitMQ Server da terminale. Di seguito i due comandi rispettivamente per l’istallazione e l’avvio:
brew install rabbitmq
rabbitmq-server
Utilizzare RabbitMQ in Spring Boot per lo scambio di messaggi in un'architettura a microservizi
Il prossimo passo consiste nel configurare RabbitMQ all’interno di Spring.
L’esempio di questo post consiste nel far comunicare 2 applicazioni Spring Boot, rappresentanti due servizi, attraverso lo scambio di messaggi su server Rabbit.
Non resta che creare i due progetti Spring Boot seguendo la procedura descritta in questo post.
Aggiungere le dipendenze
Per utilizzare RabbitMQ in Spring Boot occorre inserire la sua dipendenza all’interno del file pom.xml (progetti Maven) dell’applicazione. Aggiungiamo la dipendenza in entrambi i progetti creati.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
Aggiungere una configurazione RabbitMQ
Il passo successivo consiste nell’impostare i parametri di connessione al server RabbitMQ. Aggiungi le proprietà nel file application.yml sfruttando la configurazione di default di Spring.
spring:
rabbitmq:
username: guest
password: guest
host: localhost
Segue, la creazione di una classe di configurazione RabbitMQConfig che definisce il Bean rappresentante la coda Rabbit utilizzata per scambiare i messaggi.
Allo stesso tempo, dobbiamo definire la struttura dell’oggetto che vogliamo scambiare come messaggio, ad esempio l’oggetto Ball che rappresenta una palla. Sarà responsabilità del broker Rabbit deserializzare l’oggetto durante l’inserimento e la ricezione del messaggio, come vedremo tra poco.,
public class Ball implements Serializable {
private String color;
private Integer size;
// getter and setter
}
@Configuration
public class RabbitMQConfig {
@Bean
public Queue ballQueue() {
return new Queue("ball-queue")
}
}
Eseguire tutte le operazioni viste fino ad ora in entrambe le applicazioni Spring Boot.
Inviare un messaggio
Realizziamo una API per l’invio di un oggetto Ball da un service all’altro, implementandola all’interno di una delle due applicazioni. Chiamando l’API creata, ci aspettiamo di ricevere l’oggetto nell’altra applicazione passando dal server RabbitMQ.
Crea un nuovo controller BallController come di seguito:
@RestController
@RequestMapping("api/v1/ball")
public class BallController {
@Autowired
private Queue ballQueue;
@Autowired
private RabbitTemplate rabbitTemplate;
@PostMapping
public ResponseEntity input(@RequestBody Ball body) {
rabbitTemplate.convertAndSend(ballQueue.getName(), body);
return ResponseEntity.noContent().build();
}
}
Puoi avviare l'applicazione e fare una prova effettuando la chiamata POST api/v1/ball contenente l'oggetto, ad esempio, con cURL:
curl -X POST \
http://localhost:8080/api/v1/ball \
-H 'Content-Type: application/json' \
-d '{
"color": "RED",
"size": 5
}'
Allo stesso tempo, controlla sul server Rabbit . Per fare questo, accedi al pannello di gestione che trovi all'indirizzo http://localhost:1567, inserendo come credenziali di accesso utente guest e password guest. Troverai la coda ball-queue creata nella sezione Queues.
Recuperare un messaggio
Dobbiamo ora configurare il secondo service per recuperare e gestire i messaggi.
Per prima cosa dobbiamo impostare una porta diversa all’altro service, al fine di lanciare, al termine, entrambi i servizi. Per far questo, aggiungi alle proprietà la nuova porta, ad esempio 8081, diversa dalla porta di default 8080.
server:
port: 8081
Crea una classe BallDataConsumer che contiene un metodo receiveMessage. Aggiungeremo questo metodo all’interno della configurazione affinché venga eseguito automaticamente alla presenza di un nuovo messaggio all’interno della coda.
@Component
public class BallDataConsumer {
public void receiveMessage(Ball data) {
// Do something
System.out.println(String.format("Consuming ball data %s", data.toString()));
}
}
A questo punto dovrai modificare la classe RabbitMQConfig aggiungendo a quella presente (Queue) le nuove configurazioni:
@Configuration
public class RabbitMQConfig {
@Bean
public Queue ballQueue() {
return new Queue("ball-queue")
}
@Bean
public MessageListenerAdapter ballMessageAdapter(BallDataConsumer consumer) {
return new MessageListenerAdapter(consumer, "receiveMessage");
}
@Bean
public SimpleMessageListenerContainer ballMessageListenerContainer(ConnectionFactory connectionFactory, BallDataConsumer consumer) {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.setQueueNames(ballQueue().getName());
container.setMessageListener(ballMessageAdapter(consumer));
return container;
}
}
A questo punto abbiamo completato tutte le configurazioni e implementazioni necessarie a realizzare uno scambio di messaggi tra applicazioni Spring Boot, impiegando un’architettura a microservizi.
Il risultato dell’architettura è rappresentato dalla figura sottostante.
- Avvia il server RabbitMQ
- Avvia entrambi i servizi: assicurati che le applicazioni siano configurate con porte diverse (es: 8080 default e 8081)
- Effettua la chiamata POST all'API
- Osserva il log finale nella console
No comment yet, add your voice below!