Académique Documents
Professionnel Documents
Culture Documents
L’architecture microservices propose une solution en principe très simple : découper une application en petits services,
appelé Microservices, parfaitement autonomes, qui exposent une API REST que les autres microservices pourront
consommer.
Architecture Microservice 1
Chaque microservice est parfaitement autonome :
Chaque microserive a sa propre base de donnée, son propres serveur (Ex: Tomcat), ses propres librairies, etc.
La plupart du temps, ces microservices sont chacun dans un contenair Docker, isl sont donc totalement indépendant, y
compris vis-à-vis de la machine sur laquelle ils tournent.
Du fait du cloisonnement complet de no.s microservice on peut utiliser dans chacun la technologie que l’on veut. Le
microservice A peut être Java tandis que le microservice B est en C++ ou Node.js, l’essentiel étant qu’ils exposent une API
REST permettant d’interagir avec eux. Ceci vas nous permettre de profiter des avancés technologique sans limite de langage,
de Framework, d’environnement, etc.
Grâce aux microservice, les équipes de développement deviennent beaucoup plus autonome car tu ne sera plus obliger de
consulter l’ensemble de l’équipe pour concrétiser une idée et vérifier sa compatibilité technique avec ce font les autres. Les
équipes vont donc être autonome et aller au bout de leurs idées en utilisant la technologie de leurs choix.
Architecture Microservice 2
Les services dans l'architecture Microservices sont très spécialisés. Ils s'occupent d'une et d'une seule fonctionnalité. Dans la
MSA (MicroService Architecture), le couplage faible est primordial, à savoir que chaque microservice doit être très
indépendant à tous les niveaux. Chaque microservice possède sa propre base de données, néanmoins, on peut
rencontrez une MSA où il y a une base de données partagée.
Les microservices se base majoritairement sur l’architecture REST mais peuvent fonctionner avec tout type d’architecture
comme SOAP (Simple Object Access Protocol).
La MSA tend à obligé à utiliser un seul protocole et à s’y tenir, on a bien sûr moins de liberté.
ResponseEntity :
ResponseEntity est une classe qui hérite de HttpEntity, qui permet de retourner le code HTTP à retourner. L'intérêt de
ResponseEntity est de nous donner la main pour personnaliser le code facilement.
ResponseEntity est une extension de HttpEntity qui représente une réponse HTTP comprenant le statut, les en-têtes et le
corps. ResponseEntity vous permet de modifier la réponse avec des en-têtes et un code d'état facultatifs.
https://developer.mozilla.org/fr/docs/Web/HTTP/Status
Architecture Microservice 3
Exemple :
@RequestMapping("/handle")
public ResponseEntity<Category> handle() {
Category category = new Category();
URI location = ServletUriComponentsBuilder
.fromCurrentRequest()
.path("/{id}")
.buildAndExpand(category.getId())
.toUri();
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.setLocation(location);
responseHeaders.set("MyResponseHeader", "MyValue");
return new ResponseEntity<Category>(category, responseHeaders, HttpStatus.CREATED);
}
@RequestMapping("/handle")
public ResponseEntity<String> handle() {
URI location = ServletUriComponentsBuilder
.fromCurrentRequest()
.path("/{id}")
.buildAndExpand(category.getId())
.toUri();
return ResponseEntity.created(location).header("MyResponseHeader", "MyValue").body("Hello World");
}
Filtrage statique :
La librairie Jackson, qui nous permet de convertir nos objet Java en JSON, nous offre l’annotation @JsonIgnore, qu’il faut
mettre au dessus des propriété que nous ne voulons pas voir apparaitre dans nos objet JSON.
Quand on a beaucoup de propriété à caché on peut utiliser l’annotation @JsonIgnoreProperties(value = {”propriété1”,
”propriété2”}) au dessus de la classe concerné.
Filtrage dynamique :
Que faire si nous souhaitons afficher une propriété ou non, en fonction de qui le demande ? Pour cela, nous utilisons le filtrage
dynamique, @JsonFilter("monFiltreDynamique"), au dessus de la classe concerné, puis on effectue les autres
configurations dans notre controller comme dans le code suivant.
Partons de l’exemple de code suivant de controller :
Ce code stocke la liste des produits retournés par findAll dans une liste.
SimpleBeanPropertyFilter est une implémentation de PropertyFilter qui permet d'établir les règles de filtrage sur un Bean
donné. Ici, nous avons choisi la règle serializeAllExcept qui exclut uniquement les propriétés que nous souhaitons ignorer.
Inversement, nous pouvons procéder avec la méthode filterOutAllExcept qui marque toutes les propriétés comme étant à
ignorer, sauf celles passées en argument.
Maintenant que nous avons établi notre règle de filtrage, la ligne suivante nous permet d'indiquer à Jackson à quel Bean
l'appliquer. Nous utilisons SimpleFilterProvider pour déclarer que les règles de filtrage que nous avons créées (monFiltre)
peuvent s'appliquer à tous les Beans qui sont annotés avec monFiltreDynamique.
Jusqu'à présent, nous n'avons encore rien filtré concrètement ! Nous avons établi la règle et indiqué que cette règle ne
s'applique qu'aux Beans qui sont annotés avec monFiltreDynamique, mais nous ne l'avons pas encore appliquée. Pour cela,
nous les mettons au format MappingJacksonValue. Cela permet de donner accès aux méthodes qui nous intéressent, comme
setFilters qui applique les filtres que nous avons établis à la liste de Product.
Architecture Microservice 4
Nous retournons ensuite la liste filtrée. MappingJacksonValue n'est qu'un simple "conteneur" qui ne change absolument rien
au contenu. MappingJacksonValue est donc exactement comme produits, avec des méthodes de filtrage en plus.
JpaRepository Keywords :
Keyword Sample JPQL snippet
… where x.lastname = ?1 and
And findByLastnameAndFirstname
x.firstname = ?2
… where x.lastname = ?1 or
Or findByLastnameOrFirstname
x.firstname = ?2
findByAgeIn(Collection<Age>
In … where x.age in ?1
ages)
findByAgeNotIn(Collection<Age>
NotIn … where x.age not in ?1
age)
Source :
Requête JPQL :
Exemple :
@Query("SELECT id, nom, prix FROM Product p WHERE p.prix > :prixLimit")
En paramètre de l'annotation, nous plaçons tout simplement notre requête JPQL. L'annotation @Param permet de spécifier le
nom du paramètre que nous allons recevoir. Cette annotation est optionnelle. Si elle n'est pas utilisée, l'ordre dans lequel les
Architecture Microservice 5
arguments sont fournis est utilisé. Nous aurons alors une requête de type :
Les Exceptions :
La gestions des exceptions est essentielle pour le bon fonctionnement de notre application.
Prenons un exemple dans le cas où nous ne trouvons pas un produit demander par l’utilisateur. L’API doit lever une exception
pour indiquer que le produit n’est pas trouver et renvoyer le code de statues correspondant.
@GetMapping(value = "/Produits/{id}")
public Product afficherUnProduit(@PathVariable int id) {
Product produit = productDao.findById(id);
if(produit==null) throw new ProduitIntrouvableException("Le produit avec l'id " + id + " est INTROUVABLE. Écran Bleu si je pouvai
return produit;
}
Si la variable produits est null, nous lançons une exception ProduitIntrouvableException. En effet, nous allons créer notre
propre exception afin d'être le plus spécifique possible.
Nous allons crée un package exceptions qui va contenir tous nos exceptions personnalisé et s’est dans ce package que nous
mettrons notre exception ProduitIntrouvableException, annoté avec @ResponseStatus pour renvoyer le bon code de
statues. ProduitIntrouvableException doit hériter RuntimeException pour que Spring Boot considère qu’il s’agit d’une classe
exception.
package com.ecommerce.microcommerce.web.exceptions;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
@ResponseStatus(HttpStatus.NOT_FOUND)
Validations :
Spring propose de valider les données grâce à une dépendance spring-boot-starter-validation.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>2.6.0</version>
</dependency>
Cette librairie va nous permettre de valider les données grâce à de simples annotations, comme @Size, @NotNull, etc.
Architecture Microservice 6
Impact sur les méta-
Annotation S'applique à Vérification à l'exécution
données d'Hibernate
comprise dans l'intervalle
propriété (nombre ou
vérifie si la valeur est ajoute une contrainte de
@Max(value=) chaîne de caractères
inférieure ou égale à max vérification sur la colonne
représentant un nombre)
propriété (nombre ou
vérifie si la valeur est ajoute une contrainte de
@Min(value=) chaîne de caractères
supérieure ou égale à max vérification sur la colonne
représentant un nombre)
vérifie si la propriété
correspond à l'expression
@Pattern(regex="regexp",
propriété (String) rationnelle donnée (pour aucun
flag=)
"flag",
voir java.util.regex.Pattern)
vérifie si la taille de
propriété (tableau,
@Size(min=, max=) l'élément est comprise aucun
collection, map)
entre min et max (inclus)
exécute la validation
récursivement sur l'objet
associé. Si l'objet est une
Collection ou un tableau,
@Valid propriété (objet) les éléments sont validés aucun
récursivement. Si l'objet
est une Map, les éléments
valeur sont validés
récursivement.
vérifie si la chaîne de
caractères est conforme à
@Email propriété (String) aucun
la spécification d'une
adresse e-mail
Sources :
Architecture Microservice 7
Hibernate Validator 8.0.1.Final - Jakarta Bean Validation Reference Implementation: Reference Guide
Hibernate Validator, Annotation based constraints for your domain model - Reference Documentation
https://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/#preface
Il nous faut également indiquer dans notre contrôleur que le produit reçu de l'utilisateur est à valider. Pour ce faire, il faut ajouter
l'annotation @Valid , comme illustré ci-après :
ResponseEntity est très souvent utiliser comme type de retour de nos réponse HTTP. Exemple: ResponseEntity<Produc>
getProduct();
NB: il est conseillé d’ajouter dans le header de notre réponse http la localisation de la nouvelle ressource qui vient d’être créer,
ie que si je crée un nouveau produit par exemple dans ma base de données, si la création a été un succès je dois fournir l’URL
permettant d’accéder à mon nouveau produit créer. Exemple:
Ici, la méthode qui permet de créer un nouveau produit retourne un objet ResponseEntity<Product>, tu sais déjà pourquoi 😉.
La méthode build() permet de construire le header de notre réponse HTTP.
Architecture Microservice 8