Comment partager DTO entre microservices

1. Vue d'ensemble

Les microservices sont devenus populaires ces dernières années. L'une des caractéristiques essentielles des microservices est qu'ils sont modulaires, isolés et faciles à mettre à l'échelle. Les microservices doivent travailler ensemble et échanger des données. Pour ce faire, nous créons des objets de transfert de données partagés appelés DTO.

Dans cet article, nous présenterons les façons dont les DTO sont partagés entre les microservices.

2. Exposition d'objets de domaine en tant que DTO

Les modèles qui représentent le domaine d'application sont gérés à l'aide de microservices. Les modèles de domaine sont des préoccupations différentes, et nous les séparons des modèles de données dans la couche DAO.

La raison principale en est que nous ne voulons pas exposer la complexité de notre domaine à travers les services aux clients. Au lieu de cela, nous exposons les DTO entre nos services qui servent des clients d'application via des API REST. Alors que les DTO passent entre ces services, nous les convertissons en objets de domaine .

L'architecture orientée services ci-dessus montre schématiquement les composants et le flux des objets DTO vers Domain.

3. Partage DTO entre microservices

Prenons, par exemple, le processus de commande d'un produit par un client. Ce processus est basé sur le modèle de commande client . Regardons le processus du côté de l'architecture de service.

Disons que le service client envoie des données de demande au service de commande comme:

"order": { "customerId": 1, "itemId": "A152" }

Les services Client et Commande communiquent entre eux au moyen de contrats . Le contrat, qui est sinon une demande de service, est affiché au format JSON. En tant que modèle Java, la classe OrderDTO représente un contrat entre le service client et le service Order:

public class OrderDTO { private int customerId; private String itemId; // constructor, getters, setters }

3.1. Partage de DTO à l'aide de modules clients (bibliothèques)

Un microservice nécessite certaines informations provenant d'autres services pour traiter toute demande. Disons qu'il existe un troisième microservice qui reçoit les demandes de paiement de commande. Contrairement au service Commande, ce service nécessite différentes informations client:

public class CustomerDTO { private String firstName; private String lastName; private String cardNumber; // constructor, getters, setters }

Si nous ajoutons également un service de livraison, les informations client auraient:

public class CustomerDTO { private String firstName; private String lastName; private String homeAddress; private String contactNumber; // constructor, getters, setters }

Ainsi, placer la classe CustomerDTO dans un module partagé ne sert plus l'objectif prévu. Pour résoudre ce problème, nous abordons une méthode différente.

Dans chaque module de microservice, créons un module client (bibliothèque) et à côté de lui un module serveur :

order-service |__ order-client |__ order-server

Le module client-commande contient un DTO partagé avec le service client. Par conséquent, le module commande-client a la structure suivante:

order-service └──order-client OrderClient.java OrderClientImpl.java OrderDTO.java 

Le OrderClient est une interface qui définit un ordre Procédé de traitement de demandes de commande:

public interface OrderClient { OrderResponse order(OrderDTO orderDTO); }

Pour implémenter la méthode order , nous utilisons l' objet RestTemplate pour envoyer une requête POST au service Order:

String serviceUrl = "//localhost:8002/order-service"; OrderResponse orderResponse = restTemplate.postForObject(serviceUrl + "/create", request, OrderResponse.class);

De plus, le module commande-client est prêt à l'emploi. Il devient désormais une bibliothèque dépendante du module de service client :

[INFO] --- maven-dependency-plugin:3.1.2:list (default-cli) @ customer-service --- [INFO] The following files have been resolved: [INFO] com.baeldung.orderservice:order-client:jar:1.0-SNAPSHOT:compile

Bien entendu, cela n'a aucun but sans le module order-server pour exposer le point de terminaison du service «/ create» au client de commande:

@PostMapping("/create") public OrderResponse createOrder(@RequestBody OrderDTO request)

Grâce à ce point de terminaison de service, le service client peut envoyer une demande de commande via son client de commande. En utilisant le module client, les microservices communiquent entre eux de manière plus isolée. Les attributs du DTO sont mis à jour dans le module client. Par conséquent, la rupture de contrat est limitée aux services qui utilisent le même module client.

4. Conclusion

Dans cet article, nous avons expliqué un moyen de partager des objets DTO entre des microservices. Au mieux, nous y parvenons en créant des contrats spéciaux dans le cadre de modules clients de microservices (bibliothèques). De cette manière, nous séparons le client de service de la partie serveur qui contient la ressource API. En conséquence, il y a quelques avantages :

  • Il n'y a pas de redondance dans le code DTO entre les services
  • La rupture de contrat est limitée aux services qui utilisent la même bibliothèque cliente

Un exemple de code d'une application Spring Boot est disponible à l'adresse over sur GitHub.