1
Architectures Micro-services avec Spring Boot et Spring Cloud
Pr. Youness Abouqora
Agile Project Manager and Cloud Solutions Architect
y.abouqora@uhp.ac.ma
0661631552
2
Plan
1. Introduction
2. Création des Microservices de Base
3. Service Discovery (Netflix eureka)
4. Gestion des routes Gateway (Api Gateway et Zuul Proxy)
5. Spring Cloud Config
6. Spring Consul Consul
7. Communications Synchrone entre Micro-services
8. Fault Tolerance using Resilience4j
9. Etude de cas pratique
3
1. Introduction
Applications Web classiques : Architecture Monolithique
 Volumineuses
 Trop d’interdépendance entre les fichiers
 S’exécutant sur un serveur en respectant l’architecture (requête -
réponse)
 Format de réponse : HTML, XML ou JSON
4
1. Introduction
Problématiques
 Évolution
 Taille ↗ complexité ↗
⇒
 Après mise-à-jour : faut-il garder le code précédent ou le supprimer ?
 Déploiement
 Échec de déploiement toutes les briques de code sont remises en question
⇒
Une bonne maîtrise de tout le code est nécessaire pour la correction
 Scalabilité : extensibilité sur plus de ressources
 Verticale remplacer un serveur acceptant x nombre d’utilisateur par un autre
⇒
acceptant y nombre d’utilisateur (avec x < y) : √
 Horizontale placer l’application sur plusieurs serveurs en parallèle : X
⇒
5
1. Introduction
Architecture MicroServices
 Diviser une application en plusieurs fragments intégralement autonomes
 Chaque fragment a un objectif bien particulier
 Un fragment est appelé Web Service
 Un Web Service peut être utilisée
 par notre application monolithique existante,
 la partie serveur
 la partie client
 d’autres services Web.
 Une Architecture MicroService (MSA) est implémentée par un ensemble de Web Service
exposant une API REST
 Le terme Microservice peut designer l’architecture ou un Web Service
 L’architecture MSA permet de réaliser des applications Cloud-native : ce qui permet
d’augmenter et de diminuer le nombre de ressources a la demande en fonction du besoin.
6
1. Introduction
Architecture MicroServices
7
1. Introduction
MSA vs SOA (Service-Oriented Architecture)
 Dans une MSA, un service s’occupe d’une fonctionnalité. Dans une SOA,
un service s’occupe d’un domaine.
 La taille des services dans une MSA < La taille des services dans une SOA.
 Chaque Microservice possède sa propre base de données. Dans une SOA,
une base de données est très souvent utilisée par plusieurs services.
 Les SOA utilisent souvent SOAP. Les MSA privilégient REST.
8
1. Introduction
MSA : 3 options pour les bases de données
 Private-tables-per-service : chaque service possède un ensemble de tables
accessibles uniquement via ce service.
 Schema-per-service : chaque service possède un schéma de base de données prive
pour ce service.
 Database-server-per-service : chaque service possède son propre serveur de base
de données
Avantages d’une base de données par Microservice
 Garantir l’autonomie des services et le couplage faible.
 Chaque service peut utiliser le type de base de données le mieux adapté
à ses besoins.
2. Création des Microservices de Base
Getting Started with Spring Boot: Spring Initializr
https://start.spring.io
9
10
2. Création des Microservices de Base
Premier microservice
• Aller dans File > New > Project
• Chosir Spring Initializr
• Saisir :
- micro-service-personne dans Name,
- com.example dans Group,
- micro-service-personne dans Artifact
- com.example.demo dans Package
Cliquer sur Next
Chercher et cocher les cases correspondantes aux Spring Data JPA, MySQL
Driver, Lombok, Spring Web, Spring Boot DevTools et Eureka Discovery Client
Cliquer sur Next puis sur Finish
11
2. Création des Microservices de Base
Explication
 Le package contenant le point d’entrée de notre application (la classe contenant le
puclic static void main) est com.example.demo
 Tous les autres packages dao, model... doivent être dans le package demo.
Pour la suite, nous considérons
 une entité Personne à définir dans com.example.demo.model
 une interface DAO PersonneRepository à définir dans
com.example.demo.dao
 un controleur REST PersonneController à définir dans
com.example.demo.controller
© Achref
EL
MOUELHI
©
Créons une entité Personne dans com.example.demo.model
package com.example.demo.model;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import
lombok.RequiredArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
@Data
@Entity
@RequiredArgsConstructor
public class Personne {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long num;
@NonNull
private String nom;
@NonNull
private String
prenom;
}
H & H: Research and Training
2. Création des Microservices de Base
© Achref
EL
MOUELHI
©
Preparons notre interface DAO PersonneRepository
package com.example.demo.dao;
import org.springframework.data.jpa.repository.JpaRepository;
import com.example.demo.model.Personne;
public interface PersonneRepository extends JpaRepository<Personne,
Long> {
}
H & H: Research and Training
2. Création des Microservices de Base
© Achref
EL
MOUELHI
©
Cre´ons le controˆ leur REST suivant
@RestController
@AllArgsConstructor
public class
PersonneRestControl
ler {
private PersonneRepository personneRepository;
@GetMapping("/personnes")
public List<Personne> getPersonnes()
{ return
personneRepository.findAll();
}
@GetMapping("/personnes/{id}")
public Personne getPersonne(@PathVariable("id") long id)
{ return
personneRepository.findById(id).orElse(null);
}
@PostMapping("/personnes")
public Personne addPersonne(@RequestBody Personne personne) {
return personneRepository.save(personne);
}
H & H: Research and Training
2. Création des Microservices de Base
EL
MOUELHI
©
Dans application.properties, ajoutons les données permettant la connexion à la base de données et la
configuration de Hibernate
server.servlet.contextpath=/ws
server.port=8081
spring.datasource.url =
jdbc:mysql://localhost:3306/mic
roservice_personne?
createDatabaseIfNotExist=true
spring.datasource.username = root
spring.datasource.password =
spring.jpa.hibernate.ddl-auto = create-drop
spring.jpa.show-sql = true
spring.jpa.properties.hibernate.dialect =
org.hibernate.dialect.MySQLDialect
spring.jpa.hibernate.naming.physical-
strategy = org.hibernate.boot.model.naming.
PhysicalNamingStrategyStandardImpl
L’ajout de la propriété spring.jpa.hibernate.naming.physical-strategy permet de forcer Hibernate à utiliser
les mêmes noms pour les tables et les colonnes que les entités et les attributs.
H & H: Research and Training
2. Création des Microservices de Base
H & H: Research and Training 16 / 45
Dans application.properties, définissons un nom pour notre
application
spring.application.name=PERSONNE-SERVICE
Pour commencer, on ne publie pas le microservice
spring.cloud.discovery.enabled=false
2. Création des Microservices de Base
© Achref
EL
MOUELHI
©
Commençons par modifier le point d’entree (qui implementera l’interface
ApplicationRunner) pour alimenter la base de donne´es avec quelques données de test
@SpringBootApplication
public class MicroServicePersonneApplication {
public static void main(String[] args)
{ SpringApplication.run(MicroServicePersonneApplication.class,
args);
}
@Bean
ApplicationRunner start(PersonneRepository repository) {
return args -> {
repository.save(new Personne("El", "chama"));
repository.save(new Personne("Abouqora", "Youness"));
};
}
}
H & H: Research and Training
2. Création des Microservices de Base
Spring Boot
Pour tester
http://localhost:8081/ws/personnes
Ou http://localhost:8081/ws/personnes/1
2. Création des Microservices de Base
Aller dans File > New > Project
Chercher Spring, dans Spring Boot sélectionner Spring initializr et cliquer sur
Next >
Saisir
micro-service-adresse dans
Name, com.example dans Group,
micro-service-adresse dans
Artifact com.example.demo dans
Package
Cliquer sur Next
Chercher et cocher les cases correspondantes aux Spring Data JPA, MySQL Driver,
Lombok, Spring Web, Spring Boot DevTools, Eureka Discovery Client et
OpenFeign
Cliquer sur Next puis sur Finish
H & H: Research and Training 19 / 45
2. Création des Microservices de Base
• Explication
Le package contenant le point d’entrée de notre application (la classe
contenant le puclic static void main) est com.example.demo
Tous les autres packages dao, model... doivent être dans le package demo.
une entité com.example.demo.daoAdresse à définir dans
com.example.demo.model
une interface DAO AdresseRepository à définir dans
com.example.demo.dao
un contrôleur REST AdresseController à définir dans
H & H: Research and Training
2. Création des Microservices de Base
© Achref
EL
MOUELHI
©
Créons une entité Adresse dans com.example.demo.model
package com.example.demo.model;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import
lombok.RequiredArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
@RequiredArgsConstructor
@Data
@Entity
public class Adresse {
@Id
@GeneratedValue(strate
gy =
GenerationType.IDE
NTITY)
private Long id;
@NonNull
private String rue;
@NonNull
private String codePostal;
@NonNull
private String ville;
}
H & H: Research and Training 21 / 45
2. Création des Microservices de Base
© Achref
EL
MOUELHI
©
Comme ce microservice ne persiste pas les personnes, on va creer une classe Personne (qui n’a pas l’annotation
@Entity) dans com.example.demo.model
package com.example.demo.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import
lombok.RequiredArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
@Data
@RequiredArgsConstructor
public class Personne {
private Long num;
@NonNull
private String nom;
@NonNull
private String
prenom;
}
H & H: Research and Training
2. Création des Microservices de Base
© Achref
EL
MOUELHI
©
Modifions l’entite Adresse en ajoutant l’association avec Personne dans
@NoArgsConstructor
@AllArgsConstructor
@RequiredArgsConstructor
@Data
@Entity
public class Adresse {
@Id
@GeneratedValue(strate
gy =
GenerationType.IDE
NTITY)
private Long id;
@NonNull
private String rue;
@NonNull
private String codePostal;
@NonNull
private String ville;
@NonNull
private Long idPersonne;
@Transient
private Personne personne;
}
H & H: Research and Training
2. Création des Microservices de Base
© Achref
EL
MOUELHI
©
Preparons notre interface DAO AdresseRepository
package com.example.demo.dao;
import org.springframework.data.jpa.repository.JpaRepository;
import com.example.demo.model.Adresse;
public interface AdresseRepository extends
JpaRepository<Adresse, Long>
{
}
H & H: Research and Training 24 / 45
2. Création des Microservices de Base
EL
MOUELHI
©
Dans application.properties, ajoutons les données permettant la connexion à la base de données et la
configuration de Hibernate
server.servlet.context-path=/ws
server.port=8082
spring.datasource.url =
jdbc:mysql://localhost:3306/micr
oservice_adresse?
createDatabaseIfNotExist=true
spring.datasource.username =
root
spring.datasource.password =
root
spring.jpa.hibernate.ddl-auto =
create-drop
spring.jpa.show-sql = true
spring.jpa.properties.hibernate.
dialect =
org.hibernate.dialect.MySQLDiale
ct
spring.jpa.hibernate.naming.phys
ical-strategy =
org.hibernate.boot.model.naming.
PhysicalNamingStrategyStandardIm
pl
# microservice
spring.application.name=ADRESSE-SERVICE
spring.cloud.discovery.enabled=false
L’ajout de la propriété spring.jpa.hibernate.naming.physical-strategy permet de forcer Hibernate à utiliser
les meˆmes noms pour les tables et les colonnes que les entités et les attributs.
H & H: Research and Training
2. Création des Microservices de Base
© Achref
EL
MOUELHI
©
Commenc¸ ons par modifier le point d’entrée (qui implémentera l’interface
ApplicationRunner) pour alimenter la base de donne´es avec quelques donne´es de test
@SpringBootApplication
public class MicroServiceAdresseApplication {
public static void main(String[] args)
{ SpringApplication.run(MicroServiceAdresseApplication.class,
args);
}
@Bean
ApplicationRunner start(AdresseRepository repository) {
return args -> {
repository.save(new Adresse("prado", "13008",
"Marseille", 1L));
repository.save(new Adresse("plantes", "75014",
"Paris", 2L));
};
}
}
H & H: Research and Training 26 / 45
2. Création des Microservices de Base
H & H: Research and Training 27 / 45
2. Création des Microservices de Base
Pour activer Open Feign, ajoutons l’annotation @EnableFeignClients à la classe
de démarrage
@EnableFeignClients
@SpringBootApplication
public class
MicroServiceAdresseApp
lication {
public static void main(String[] args)
{ SpringApplication.run(MicroServiceAdresseApplication.class,
args);
}
@Bean
ApplicationRunner start(AdresseRepository repository) {
return args -> {
repository.save(new Adresse("49 Av. Lalla aicha",
"20000", "Rabat", 1L));
repository.save(new Adresse("380 Bd Brahim Roudani",
"10000", "Casablanca", 2L));
};
}
}
Créons une interface cliente PersonneRestClient qui va assurer la communication avec
le premier microservice
package com.example.demo.openfeign;
import java.util.List;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import com.example.demo.model.Personne;
@FeignClient(name = "PERSONNE-SERVICE")
public interface PersonneRestClient {
@GetMapping("/ws/personnes")
public List<Personne>
getPersonnes();
@GetMapping("/ws/personnes/
{id}")
public Personne
getPersonne(@PathVariable("id")
H & H: Research and Training
2. Création des Microservices de Base- OpenFeign
H & H: Research and Training 29 / 45
Créons un contrôleur REST AdresseRestController
dans lequel nous injectons AdresseRepository
@RestController
@AllArgsConstructor
public class
AdresseRestControll
er {
private
AdresseReposito
ry
adresseReposito
ry;
2. Création des Microservices de Base
Pour lier les adresses aux personnes, injectons aussi
PersonneRestClient
@RestController
@AllArgsConstructor
public class
AdresseRestControll
er {
private PersonneRestClient personneRestClient;
private AdresseRepository adresseRepository;
}
H & H: Research and Training
2. Création des Microservices de Base
© Achref
EL
MOUELHI
©
Ajoutons maintenant les trois actions suivantes
@GetMapping("/adresses")
public List<Adresse> getAdresses() {
var adresses = adresseRepository.findAll();
for (Adresse a : adresses) {
a.setPersonne(personneRestClient.getPerson
ne(a.getIdPersonne()));
}
return adresses;
}
@GetMapping("/adresses/{id}")
public Adresse getAdresse(@PathVariable("id") long id) {
var a = adresseRepository.findById(id).orElse(null);
a.setPersonne(personneRestClient.getPersonne(a.getIdPerso
nne()));
return a;
}
@PostMapping("/adresses")
public Adresse addAdresse(@RequestBody Adresse adresse) {
return adresseRepository.save(adresse);
}
H & H: Research and Training
2. Création des Microservices de Base
32
Démarrer l’application
Vérifier, dans la console, que les tuples de la classes de démarrage ont
été insérés
Faire une requête GET à http://localhost:8082/ws/adresses lance
une exception car les microservices ne sont pas déclarés
H & H: Research and Training
34 / 45
2. Création des Microservices de Base
33
Démarrer l’application
Vérifier, dans la console, que les tuples de la classes de démarrage ont
été insérés
Faire une requête GET à http://localhost:8082/ws/adresses lance
une exception car les microservices ne sont pas déclarés
Pour résoudre le probleme précédent
Il faut créer un projet Eureka Discovery (Spring Cloud).
H & H: Research and Training
34 / 45
3. Service Discovery (netflix eureka)
34
H & H: Research and Training
34 / 45
3. Service Discovery (netflix eureka)
Aller dans File > New > Other
Chercher Spring, dans Spring Boot sélectionner Spring Starter Project et cli-
quer sur Next >
Saisir
eureka-service dans Name,
com.example dans Group,
eureka-service dans
Artifact
com.example.demo dans
Package
Cliquer sur Next
Chercher et cocher les cases
correspondantes a
` Eureka Server et
DevTools
H & H: Research and Training
3. Service Discovery (netflix eureka)
© Achref
EL
MOUELHI
©
Commenc¸ ons par activer Eureka Server dans la classe de demarrage
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.
EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class
EurekaServiceApplicati
on {
public static void main(String[] args)
{ SpringApplication.run(EurekaServiceApplication.class,
args);
}
}
H & H: Research and Training
3. Service Discovery (netflix eureka)
37
Les propriétés à ajouter dans application.properties
server.port=8761
eureka.client.fetch-registry=false
eureka.client.register-with-
eureka=false
8761 : nume´ro de port par de´faut d’Eureka
eureka.client.fetch-registry=false : pour ne
pas enregistrer le serveur en tant que client
eureka.client.register-with-eureka=false : pour
ne pas l’enregistrer dans le registre des services
H & H: Research and Training
37 / 45
3. Service Discovery (netflix eureka)
Explication
38
Dans application.properties de micro-service-personne et
micro-service-adresse, mettons la propriété suivante à true
spring.cloud.discovery.enabled=true
Pour tester
1 démarrer le projet eureka-service
2
3
H & H: Research and Training
38 / 45
démarrer le projet micro-service-personne
démarrer le projet micro-service-adresse
3. Service Discovery (netflix eureka)
H & H: Research and Training
Allez à http://localhost:8082/ws/adresses et vérifiez qu’on récupère les adresses avec les
personnes
[
{
"id": 1,
"rue": "paradis",
"codePostal": "13006",
"ville": "Rabat",
"idPersonne": 1,
"personne": {
"num": 1,
"nom": "El",
"prenom": "Chama"
}
},
{
"
i
d
"
:
2
,
"rue": "plantes",
"codePostal": "75014",
"ville":
"Casablanca",
"idPersonne": 2,
"personne": {
"num": 2,
3. Service Discovery (netflix eureka)
Remarque
1
2
H & H: Research and Training 40 / 45
Allez à http://localhost:8761/
Vérifiez la présence de deux services dans
Instances currently registered with
Eureka
3. Service Discovery (netflix eureka)
41
H & H: Research and Training
41 / 45
4. Passerelle de services (Api Gateway)
Constat
Chaque microservice a sa propre URL : host + port + ...
Comment utiliser la même URL avec un path unique pour chaque microservice?
Utiliser le routage dynamique avec le Gateway
42
4. Passerelle de services (Api Gateway)
Explication
Une passerelle de services sert d'intermédiaire entre un
service et le client qui l'appelle. Le client ne parle qu'à une
seule URL gérée par la passerelle de services. La passerelle de
services distingue le chemin provenant de l'appel du client et
détermine le service que le client tente d'invoquer. exemples
de problèmes transversaux pouvant être implémentés dans
une passerelle de services incluent :
- Routage statique
- Routage dynamique
- Authentification et autorisation
- Collecte et journalisation des métriques
H & H: Research and Training 43 / 45
Aller dans File > New > Project
Chercher Spring, dans Spring Boot sélectionner Spring Initializr et cli quer
sur Next >
Saisir
gateway-routing dans Name,
com.example dans Group,
gateway-routing dans
Artifact com.example.demo
dans Package
Cliquer sur Next
Chercher et cocher les cases
correspondantes aux Reactive
Gateway, DevTools et
Eureka Discovery Client
Cliquer sur Next puis sur Finish
4. Gestion des routes Gateway : Routage dynamique
© Achref
EL
MOUELHI
©
Spring Boot
Ajoutons le bean suivant dans la classe de démarrage pour activer et utiliser le routage dynamique
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.ReactiveDiscoveryClient;
import
org.springframework.cloud.gateway.discovery.DiscoveryClientRouteDefinitionL
ocator;
import org.springframework.cloud.gateway.discovery.DiscoveryLocatorProperties;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class GatewayRoutingApplication {
public static void main(String[] args)
{ SpringApplication.run(GatewayRoutingApplication.class,
args);
}
@Bean
DiscoveryClientRouteDefinitionLocator dynamicRoute(
ReactiveDiscoveryClient rdc,
DiscoveryLocatorProperties dlp) {
return new
DiscoveryClientRouteDefinitionLocator(rdc,
dlp);
}
}
H & H: Research and Training 44 / 45
4. Gestion des routes Gateway : Routage dynamique
EL
H & H: Research and Training 45 / 45
Les propriétés à ajouter dans application.properties
server.port=8080
spring.application.name=GATEWAY
spring.cloud.discovery.enabled=true
eureka.instance.prefer-ip-address=true
4. Gestion des routes Gateway : Routage dynamique
46
Spring Boot
Ordre de lancement des projets
1
2
3
4
H & H: Research and Training
45 / 45
démarrer le projet eureka-service
démarrer le projet micro-service-personne
démarrer le projet micro-service-adresse
démarrer le projet gateway
4. Gestion des routes Gateway : Routage dynamique
Pour tester
Pour récupérer la liste d’adresses :
http://localhost:8080/ADRESSE-SERVICE/ws/adresses
Pour récupérer la liste de personnes :
http://localhost:8080/PERSONNE-SERVICE/ws/personnes
47
5. Spring Cloud Config
Explication
Dans une architecture microservices, plusieurs services s'exécutent en même
temps, sur des processus différents, avec chacun sa propre configuration et ses
propres paramètres. Spring Cloud Config fournit un support côté serveur et côté
client pour externaliser les configurations dans un système distribué. Grâce au
service de configuration, il est possible d'avoir un endroit centralisé pour gérer les
propriétés de chacun de ces services.
-
Aller dans File > New > Project
Chercher Spring, dans Spring Boot sélectionner Spring Initializr et cli quer sur
Next >
Saisir
config-service dans Name,
com.example dans Group,
config-service dans Artifact
com.example.demo dans Package
Cliquer sur Next
Chercher et cocher les cases
correspondantes Config Server et
DevTools
Cliquer sur Next
H & H: Research and Training
5. Spring Cloud Config
© Achref
EL
MOUELHI
©
Commençons par activer Eureka Server dans la classe de démarrage
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.
EnableEurekaServer;
@SpringBootApplication
@EnableConfigServer
public class
EurekaServiceApplicati
on {
public static void main(String[] args)
{ SpringApplication.run(EurekaServiceApplication.class,
args);
}
}
H & H: Research and Training
5. Spring Cloud Config
50
37 / 45
Les propriétés à ajouter dans application.properties
server.port=8888
spring.cloud.config.server.git.uri=file://$
{user.home}/cloud-config
spring.cloud.config.server.git.default-label=main
5. Spring Cloud Config
Création du repository git : cloud-config
Lancer git bash :
- cd C:
- cd Users/Youness Abouqora
- mkdir cloud-config
- cd cloud-config
- ls
- git init
51
37 / 45
5. Spring Cloud Config
Creation du repository git : cloud-config
Lancer git bash :
cd C:
cd Users/Youness Abouqora
cd cloud-config
code application.properties
Le fichier application.properties contient tout les parametres de configurations
qui sont commun a tout les microservices.
Lancer git bash :
cd C:/
cd Users/Youness Abouqora
cd cloud-config
git status
git add .
git commit –m "first commit"
Creation du repository git : cloud-config
52
37 / 45
5. Spring Cloud Config
Le répertoire de configuration doit être un répertoire git.
Pour cela:
Ouvrir le terminal avec IntelliJ et naviguer vers ce répertoire.
Initialiser votre répertoire: git init
Créer une entrée racine dans le repository: git add .
Faire un commit: git commit -m "bien ajoutee"
Creation du repository git : cloud-config
Les propriétés à ajouter dans application.properties
server.port=8888
spring.cloud.config.server.git.uri=file:./src/mai
n/resources/cloud-config
Créer le répertoire config-cloud à l'arborescence src/main/resources
Créer dans ce répertoire le fichier application.properties dans lequel vous insérez l'instruction
suivante:
Ce fichier sera partagé entre tous les microservices utilisant ce service de configuration.
global=xxxxx
53
37 / 45
Ajouter la dependance spring-cloud-starter-config dans le
microservices personne-service, adresse-service, eureka-service et
gateway-service
<dependency>
<groupId>
org.springframework.cloud
</groupId>
<artifactId>
spring-cloud-starter-config
</artifactId>
</dependency>
5. Spring Cloud Config
Les propriétés à ajouter dans application.properties de MS personne-
service
spring.application.name=PERSONNE-SERVICE
spring.config.import=optional:configserver:http:/
/localhost:8888/
54
5. Spring Cloud Config
Pour tester le MS personne-service configuration:
http://http://localhost:8888/personne-service/master
55
6. Spring Cloud Consul
Explication
Consul fournit un support de premier ordre pour la découverte de services, la vérification de l'état
de santé, le stockage K/V et les centres de données multiples.
Consul.io
Agent
consul
Serveur
Consul
Service des
adresses
Service des
personnes
■ Agent consulaire
• Bilan de santé
• Demandes de
renseignements
■ Serveur Consul
• Données du
magasin
• Répondre aux
questions
• Élection du chef
de file (Leader
Election)
56
6. Spring Cloud Consul
Configuration
Service Registration
Service Discovery
Consul
Spring Boot
Application
Spring Cloud
Consul Service Health
Contrôle Déploiement Configuration
• Mise à jour en cours
d'exécution
• Pas de configuration
locale
• Découverte
dynamique des points
d'extrémité
• L'ordre de départ n'a
pas d'importance
• Un déploiement
simple
• Séparation des
environnements
• Découvrir les
services à surveiller
• La santé du service est
plus importante que la
santé d'une seule
instance.
H & H: Research and Training 57 / 45
6. Spring Cloud Consul
Download et install consul.io
Ouvrez l’invite du commande dans le rep d’installation et lancez la commande : consul.exe
agent -dev
https://developer.hashicorp.com/consul/install
58
6. Spring Cloud Consul
Allez à http://localhost:8500/
59
37 / 45
Ajouter la dependance spring-cloud-starter-consul-discovery dans
le microservices personne-service, adresse-service et gateway-service
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-
discovery</artifactId>
</dependency>
5. Spring Cloud Consul
Les propriétés à ajouter dans application.properties de MS personne-
service
spring.cloud.consul.port=8500
spring.cloud.consul.host=localhost
spring.cloud.consul.discovery=PERSONNE-SERVICE
H & H: Research and Training 60 / 45
6. Spring Cloud Consul/configuration distribuée
Download et install consul.io
Ouvrez l’invite du commande dans le rep d’installation et lancez la commande : consul.exe
agent -dev
https://developer.hashicorp.com/consul/install
Dans application.yaml, ajoutons les données permettant la configuration du cunsul et importation des
key-value store
spring:
application:
name: PERSONNE-SERVICE
config:
import:"optional:consul:localhost:8500"
cloud:
consul:
host: localhost
port: 8500
discovery: PERSONNE-SERVICE
config:
format: YAML
prefix: config
default-context: personne-service
data-key: data
H & H: Research and Training
6. Spring Cloud Consul/configuration distribuée
Ajouter la configuration suivante dans le key-value store de Consul
db:
url: jdbc:mysql://localhost:3306/personne-service?
createDatabaseIfNotExist=true
username: root
password: root
Dans application.yaml, ajoutons les données permettant la connexion à la base de données et la
configuration de Hibernate
datasource:
url: ${db.url}
username: ${db.username}
password: ${db.password}
jpa:
hibernate:
ddl-auto: create-drop
naming:
physical-strategy:
org.hibernate.boot.model.naming.PhysicalNamingSt
rategyStandardImpl
show-sql: true
properties:
hibernate:
format_sql: true
server:
port: 8081
servlet:
context-path: /api
H & H: Research and Training
6. Spring Cloud Consul/configuration distribuée
63
7. Communications Synchrone entre Micro-services - RestTemplate
RestTemplate
RestTemplate est un client synchrone fourni par Spring Framework pour effectuer des requêtes HTTP. Il simplifie
l'interaction avec les services web RESTful en fournissant des méthodes pour diverses opérations HTTP, telles
que GET, POST, PUT, DELETE, etc. Ce client dispose de plusieurs méthodes, telles que getForObject(),
getForEntity(), exchange()
@Bean
public RestTemplate APIRestTemplate(RestTemplateBuilder
builder) {
return
builder.rootUri("http://localhost:8081/api").build();
}
Personne personne =
restTemplate.getForObject("/personnes/{id}",
Personne.class,1);
logger.info("Personnes trouvée: {}", personne);
Map<String, Object> parameters = Map.of("id", 1);
ResponseEntity<Personne> entity =
restTemplate.getForEntity("/personnes/{id}", Personne.class,
parameters);
logger.info("Personnes trouvée: {}", entity.getBody());
logger.info("headers trouvée: {}: {}", entity.getHeaders());
Retrieving data
64
7. Communications Synchrone entre Micro-services - RestTemplate
Personne request = new Personne("Rami", "Said");
Product personne = restTemplate.postForObject("/personnes",
request, Personne.class);
logger.info("Created product: {}", personne);
Personne request = new Personne(“Rami“,”Said”);
HttpEntity<Personne> httpEntity = new HttpEntity<>(request,
null);
RequestEntity<Personne> entity =
restTemplate.exchange("/personnes/1", HttpMethod.PUT,
httpEntity, Personne.class);
logger.info("Updated personne: {}", entity.getBody());
Send data
65
7. Communications Synchrone entre Micro-services - RestTemplate
@Service
public class AdresseService {
@Autowired
private AdresseRepository adresseRepository;
@Autowired
private RestTemplate restTemplate;
private final String URL = "http://localhost:8081/SERVICE-PERSONNE";
public List<AdresseResponse> findAllAdresses() {
List<Adresse> adresses = adresseRepository.findAll();
ResponseEntity<Personne[]> response = restTemplate.getForEntity(this.URL + "/api/personnes", Personne[].class);
Personne[] personnes= response.getBody();
return personnes.stream().map((Adresse adresse) -> mapToAdresseResponse(adresse, personnes)).toList();
}
}
// this function allow the change the Car Entity to A Model that we will send ot the client side using the @Builder
Annotation
private Adresse Response mapToAdresseResponse (Adresse adresse, Personne[] personnes) {
Personne foundPersonne = Arrays.stream(personnes)
.filter(personne -> personne.getId().equals(adresse.getIdPersonne()))
.findFirst()
.orElse(null);
return AdresseResponse.builder()
.id(adresse.getId())
.rue(adresse.getRue())
.personne(foundPersonne)
.codePostal(adresse.getCodePostal())
.ville(adresse.getVille())
.build();
}
Créons un Service
AdresseService dans
lequel nous
injectons les
fonctions suivantes
66
7. Communications Synchrone entre Micro-services - RestTemplate
// this function allow the change the Car Entity to A Model that we will send ot the client side using the @Builder
Annotation
private Adresse Response mapToAdresseResponse (Adresse adresse, Personne[] personnes) {
Personne foundPersonne = Arrays.stream(personnes)
.filter(personne -> personne.getId().equals(adresse.getIdPersonne()))
.findFirst()
.orElse(null);
return AdresseResponse.builder()
.id(adresse.getId())
.rue(adresse.getRue())
.personne(foundPersonne)
.codePostal(adresse.getCodePostal())
.ville(adresse.getVille())
.build();
}
public AdresseResponse findById(Long id) throws Exception {
Adresse adresse = adresseRepository.findById(id).orElseThrow(() -> new Exception("Invalid Car Id"));
Client client = restTemplate.getForObject(this.URL + "/api/pers/" + adresse.getIdPersonne(), Personne.class);
return AdresseResponse.builder()
.id(adresse.getId())
.rue(adresse.getRue())
.personne(foundPersonne)
.codePostal(adresse.getCodePostal())
.ville(adresse.getVille())
.build(); }
67
37 / 45
5. Communications Synchrone entre Micro-services - RestTemplate
Ajouter la calsse PersonneRestTemplate dans le MS Adresse-service
@Service
public class PersonneRestTemplate {
private final RestTemplate restTemplate;
@Autowired
public PersonneRestTemplate(RestTemplateBuilder builder) {
this.restTemplate = builder
.rootUri("http://localhost:8081")
.build();
}
}
Dans PersonneRestTemplate, ajoutons la methode getAdressesDetails et un Bean
private PersonneRestTemplate personneRestTemplate;
@GetMapping("/adressesDet/{id}")
public ResponseEntity<AdresseResponse>
getAdressesDetails(@PathVariable("id") long id){
AdresseResponse adresse=
adresseService.getAdresseById(id);
return ResponseEntity.status(HttpStatus.OK).body(adresse);
}
68
7. Programmation reactive - WebFlux
WebClient
Contrairement au modèle bloquant du framework Spring MVC, Spring WebClient
est conçu pour traiter un grand nombre de requêtes simultanément, avec une
faible latence et un débit élevé. Il fournit un modèle de programmation réactive,
qui permet au framework de traiter les demandes comme des flux d'événements,
plutôt que comme des demandes individuelles.
Constat
RestTemplate est intrinsèquement bloquant, ce qui n'est pas idéal pour les
systèmes réactifs modernes à hautes performances, où les E/S non bloquantes
peuvent offrir une meilleure évolutivité et une meilleure réactivité. Par
conséquent, WebClient a été introduit en tant qu'alternative moderne et non
bloquante.
69
7. Communications Synchrone entre Micro-services - WebClient
Ajouter la dependance spring-cloud-starter-webFlux dans le
microservices adresse-service
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifa
ctId>
</dependency>
WebClient webClient = WebClient.create() ; // Avec
un URI vide
WebClient webClient =
WebClient.create("http://localhost:8081/api") ; //
Avec l'URI racine spécifié
La méthode create() est une méthode surchargée et peut éventuellement
accepter une URL de base pour les requêtes.
70
7. Communications Synchrone entre Micro-services - WebClient
@Configuration
@PropertySource("classpath:application.properties")
public class AppConfiguration {
@Value("${personneService.base.url}")
private String personneBaseUrl;
@Bean
public ModelMapper modelMapperBean(){
return new ModelMapper();
}
@Bean
public WebClient webClient(){
return WebClient
.builder()
.baseUrl(personneBaseUrl)
.defaultCookie("cookie-name", "cookie-value")
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.build();
}
}
Créons une classe AppConfiguration
Ajouter la configuration suivante dans le application.properties
personneService.base.url=http://localhost:8081/api
Dans AdresseService, ajoutons la methode getAdresseById(long id)
H & H: Research and Training
6. Communications Synchrone entre Micro-services - WebClient
public AdresseResponse getAdresseById(long id){
Optional<Adresse> adresse =
adresseRepository.findById(id);
AdresseResponse adresseResponse= mapper.map(adresse,
AdresseResponse.class);
PersonneResponse personneResponse=
webClient.get()
.uri("/personnes/{id}",adresseResponse.getIdPersonne())
.retrieve()
.bodyToMono(PersonneResponse.class)
.block();
adresseResponse.setPersonne(personneResponse);
return adresseResponse;
}
Dans AdresseController, ajoutons la methode getAdressesDetails et un Bean
private AdresseService adresseService;
@GetMapping("/adressesDet/{id}")
public ResponseEntity<AdresseResponse>
getAdressesDetails(@PathVariable("id") long id){
AdresseResponse adresse=
adresseService.getAdresseById(id);
return ResponseEntity.status(HttpStatus.OK).body(adresse);
}
Dans AdresseService, ajoutons la methode getAdresseById(long id)
H & H: Research and Training
6. Communications Synchrone entre Micro-services - WebClient
public AdresseResponse getAdresseById(long id){
Optional<Adresse> adresse =
adresseRepository.findById(id);
AdresseResponse adresseResponse= mapper.map(adresse,
AdresseResponse.class);
PersonneResponse personneResponse=
webClient.get()
.uri("/personnes/{id}",adresseResponse.getIdPersonne())
.retrieve()
.bodyToMono(PersonneResponse.class)
.block();
adresseResponse.setPersonne(personneResponse);
return adresseResponse;
}
Dans AdresseController, ajoutons la methode getAdressesDetails et un Bean
private AdresseService adresseService;
@GetMapping("/adressesDet/{id}")
public ResponseEntity<AdresseResponse>
getAdressesDetails(@PathVariable("id") long id){
AdresseResponse adresse=
adresseService.getAdresseById(id);
return ResponseEntity.status(HttpStatus.OK).body(adresse);
}
73
7. Communications Synchrone entre Micro-services - WebClient
@Bean
public WebClient APIWebClient(WebClient.Builder builder
builder) {
return
builder.baseUri("http://localhost:8081/api").build();
}
Mono<Product> personneMono = webClient
.get()
.uri(builder -> builder
.path("/personnes/1")
.build())
.retrieve()
.bodyToMono(Personne.class);
productMono.subscribe(product -> logger.info("Found product:
{}", product));
webClient
.get()
.uri(builder -> builder
.pathSegment("products", "{id}") // Add a URL
variable
.build(Map.of("id", 1))) // Map each URL variable
.retrieve()
.bodyToMono(Product.class)
.subscribe(product -> logger.info("Found product: {}",
product));
Retrieving data
74
7. Communications Synchrone entre Micro-services - WebClient
CreateProductRequest request = new
CreateProductRequest("Banana");
webClient
.post()
.uri("/products/add")
.bodyValue(request)
.retrieve()
.bodyToMono(Product.class)
.subscribe(product -> logger.info("Created product: {}",
product));
UpdateProductRequest request = new
UpdateProductRequest("Bananaaaaa");
webClient
.put()
.uri("/products/101")
.bodyValue(request)
.retrieve()
.bodyToMono(Product.class)
.subscribe(product -> logger.info("Updated product: {}",
product));
Send data
75
7. Fault Tolerance using Resilience4j
Introduction
Dans un contexte de microservices, il est courant de
rencontrer des déviations lors de son fonctionnement
en temps réel. Cela peut se manifester par des temps de
réponse prolongés, des problèmes de réseau, des
échecs d'appels REST, ou encore des surcharges dues à
un volume élevé de requêtes, parmi d'autres
complications. Pour gérer ces types d'erreurs
potentielles, il est essentiel d'intégrer un mécanisme de
tolérance aux pannes dans notre application. À cette fin,
nous nous appuierons sur la bibliothèque Resilience4j.
resilience4j.io
76
7. Fault Tolerance using Resilience4j
Resilience4j
Resilience4j is a lightweight, easy-to-use fault tolerance
library inspired by Netflix Hystrix, but designed for Java 8
and functional programming
resilience4j.io
Design pattern
Les patterns de résilience des clients sont axés sur la protection d'un client de ladite ressource (un autre appel de
microservice ou une base de données) en cas de défaillance de la ressource distante. Le but de ces modèles est de
permettre au client d'échouer rapidement (Fail-fast), de ne pas consommer de ressources, telles que les connexions
de base de données et les pools de threads, et d'empêcher le problème du service distant de se propager « en
amont » aux consommateurs du client.
• Bulkhead : limit the number of concurrent requests within a particular period. Limits concurrent executions
• TimeLimiter : the process of setting a time limit for a Microservice to respond limit duration of execution
• Rate Limiter : limits the number of incoming requests for a given period. Limit executions/period
• Circuit Breaker: is a pattern in developing the Microservices based applications in order to tolerate any fault.
Temporary blocks possible failures
• Retry : retries failed service calls to increase the chance of getting response. repeats failed executions
77
7. Fault Tolerance using Resilience4j- Design pattern
Bulkhead
Ratelimiter
B ne pouvant encaisser
plus de X appels sur une
durée, on va limiter le
nombre d’appels sur une
période donnée et
rejeter les autres appels
plutôt que les traiter et
crasher
A droite, on a limité à 2
appels concurrents de
B (qui est lent) pour
éviter de saturer les
threads de traitement
de B qui est limité en
ressources
Annotation resilience4j :
@Bulkhead(name=BULKHEAD_NAME)
Annotation resilience4j :
@RateLimiter(name=RATELIMITER_NAME)
78
7. Fault Tolerance using Resilience4j- Design pattern
Timelimiter
La méthode B a mis trop
de temps à renvoyer un
résultat.
Circuit breaker
Gérer la latence et les
échecs des webservices
utilisés par votre
application
Retry
Le premier appel à B a
échoué et le second a
renvoyé un succès
Annotation resilience4j :
@Retry(name=RETRY_NAME)
Annotation resilience4j :
@Timelimiter(name=TIMELIMITER_NAME)
Annotation resilience4j : @CircuitBreaker(name=CIRCUIT_BREAKER_NAME)
79
37 / 45
Ajouter les dependances spring-cloud-starter-actuator, spring-
cloud-starter-circuitbreaker-resilience4j dans le microservice
adresse-service
<dependency>
<groupId>org.springframework.boot</
groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency> <groupId>org.springframework.cloud</
groupId>
<artifactId>spring-cloud-starter-circuitbreaker-
resilience4j</artifactId>
</dependency>
7. Fault Tolerance using Resilience4j- Config
80
37 / 45
5. Actuator
Les propriétés à ajouter dans application.properties de MS adresse-
service
management:
health:
## active circuit breaker
circuitbreakers:
enabled: true
endpoints:
web:
exposure:
include: health
endpoint:
health:
show-details: always
81
37 / 45
Les propriétés à ajouter dans application.yaml pour circuitbreaker
resilience4j:
circuitbreaker:
configs:
default
// instances:
// adresseService:
registerHealthIndicator: true
eventConsumerBufferSize: 10
failureRateThreshold: 50 #indicates that if 50% of requests are getting failed,
open the circuit ie. Make the Circuit Breaker state as Open.
minimumNumberOfCalls: 5 #indicates that we need at least 5 calls to calculate
the failure rate threshold.
automaticTransitionFromOpenToHalfOpenEnabled: true #indicates that don’t switch
directly from the open state to the closed state, consider the half-open state
also.
waitDurationInOpenState: 3s #indicates the waiting time interval while switching
from the open state to the closed state.
permittedNumberOfCallsInHalfOpenState: 3 #indicates that when on half-open
state, consider sending 4 requests. If 80% of them are failing, switch circuit
breaker to open state.
slidingWindowSize: 10 #indicates that if 80% of requests out of 10 (it means 8)
are failing, open the circuit.
sliding-window-type: count_based # indicates that we are using COUNT_BASED
sliding window. Another type is TIME_BASED.
7. Fault Tolerance using Resilience4j- config
Ajoutons maintenant les
l’annotation
@CircuitBreaker et la
methode
getDefaultAdress()
public static final String ADRESSE_SERVICE="adresseService";
@GetMapping("/adresses")
@CircuitBreaker(name=“default”, fallbackMethod = "getDefaultAdresses")
public List<Adresse> getAdresses() {
var adresses = adresseRepository.findAll(); for
(Adresse a : adresses) {
a.setPersonne(personneRestClient.getPersonne(a.getId
Personne()));
}
return adresses;
}
@GetMapping("/adresses/{id}")
@CircuitBreaker(name=ADRESSE_SERVICE, fallbackMethod =
"getDefaultAdress")
public Adresse getAdresse(@PathVariable("id") long id) { var a =
adresseRepository.findById(id).orElse(null);
a.setPersonne(personneRestClient.getPersonne(a.getIdPersonne()));
return a;
}
@PostMapping("/adresses")
public Adresse addAdresse(@RequestBody Adresse adresse) { return
adresseRepository.save(adresse);
}
public List<Adresse> getDefaultAdresses(Exception e){
return Stream.of(
Adresse.builder()
.rue("rue inconue")
.codePostal("code inconue")
.ville("ville inconue")
.idPersonne(0L)
.personne(null)
.build()
).collect(Collectors.toList());
H & H: Research and Training
7. Fault Tolerance using Resilience4j- Config
83
37 / 45
Les propriétés à ajouter dans application.yaml pour retry
resilience4j:
retry:
instances:
adresseService:
max-attempts: 5
wait-duration: 5s
7. Fault Tolerance using Resilience4j- Config
Ajoutons maintenant dans AdresseController les l’annotation @RateLimiter
@Retry(name = ADRESSE_SERVICE, fallbackMethod = "getMessageFallBack")
et la methode getMessageFallBack()
public String getInvoiceFallback(Exception e) {
log.info("---RESPONSE FROM FALLBACK METHOD---");
return "SERVICE IS DOWN, PLEASE TRY AFTER SOMETIME !!!";
}
Une fois les 5 tentatives terminées, vous devriez voir le message « -RESPONSE DE LA MÉTHODE DE RETOUR- » dans la
console. Ce message indique que la méthode de secours a été appelée.
84
37 / 45
Les propriétés à ajouter dans application.yaml pour ratelimiter
resilience4j:
ratelimiter:
instances:
adresseService:
limitForPeriod: 2
limitRefreshPeriod: 15s
registerHealthIndicator: true
7. Fault Tolerance using Resilience4j- Config
Ajoutons maintenant dans AdresseController les l’annotation @RateLimiter
@RateLimiter(name = ADRESSE_SERVICE)
et la methode getMessageFallBack()
public ResponseEntity<String> getMessageFallBack(RequestNotPermitted exception) {
return ResponseEntity.status(HttpStatus.TOO_MANY_REQUESTS)
.body("Too many requests : No further request will be accepted. Please try
after sometime");
}
Une fois que vous avez actualisé plus de 2 fois en l'espace de 3 secondes, vous devriez voir apparaître le message « Too
many requests : No further request will be accepted. Please try after sometime »
85
37 / 45
Les propriétés à ajouter dans application.yaml pour bulkhead
resilience4j:
bulkhead:
instances:
adresseService:
max-concurrent-calls: 5 #indicates that if the number of concurrent calls exceed
5, activate the fallback method.
max-wait-duration: 0 #indicates that don’t wait for anything, show response
immediately based on the configuration.
server:
tomcat:
threads:
max: 5
7. Fault Tolerance using Resilience4j- config
Ajoutons maintenant dans AdresseController les l’annotation @Bulkhead
@Bulkhead(name = ADRESSE_SERVICE)
public List<Adresse> getAdresses(){
…
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
…
return adresses;
}
86
37 / 45
Les propriétés à ajouter dans application.yaml pour timelimiter
resilience4j.timelimiter:
configs:
default:
limitForPeriod: 2
limitRefreshPeriod: 15s
timeoutDuration: 5s
registerHealthIndicator: true
eventConsumerBufferSize: 100
instances:
backendA:
baseConfig: default
backendB:
baseConfig: default
limitForPeriod: 3
7. Fault Tolerance using Resilience4j- default Config
resilience4j:
timelimiter:
instances:
adresseService:
timeout-duration: 1ms #indicates that the maximum amount of time a request can
take to respond is 1 millisecond
cancel-running-future: false #indicates that do not cancel the Running
Completable Futures After TimeOut.
Ajoutons maintenant dans AdresseController l’annotation @TimeLimiter
@Timelimiter(name = ADRESSE_SERVICE)
à ajouter egalement dans application.yaml pour default configs
87
37 / 45
Les propriétés à ajouter dans application.yaml pour timelimiter
resilience4j.timelimiter:
configs:
default:
limitForPeriod: 2
limitRefreshPeriod: 15s
timeoutDuration: 5s
registerHealthIndicator: true
eventConsumerBufferSize: 100
instances:
backendA:
baseConfig: default
backendB:
baseConfig: default
limitForPeriod: 3
7. Tester avec JMeter
resilience4j:
timelimiter:
instances:
adresseService:
timeout-duration: 1ms #indicates that the maximum amount of time a request can
take to respond is 1 millisecond
cancel-running-future: false #indicates that do not cancel the Running
Completable Futures After TimeOut.
Ajoutons maintenant dans AdresseController l’annotation @TimeLimiter
@Timelimiter(name = ADRESSE_SERVICE)
à ajouter egalement dans application.yaml pour default configs
88
Etude de cas pratique : Mise en oeuvre d’une architecture microservices [Micro Services | Spring boot 3 | Spring Cloud
89
Etude de cas pratique : Mise en oeuvre d’une architecture microservices [Micro Services | Spring boot 3 | Spring Cloud
API Gateway
Le passerelle API sert de point d'entrée unique pour toutes les demandes des clients, en
les gérant et en les acheminant vers les microservices approprié
Config Server
Le serveur de configuration centralise la gestion de la configuration pour tous les
microservices, ce qui simplifie la maintenance des applications et la cohérence entre les
environnements.
Discovery Server
Le serveur de découverte assure l'enregistrement et la découverte des services, ce qui
permet une communication transparente entre les services au sein de l'écosystème de
microservices
Student Microservice
Le microservice Student est responsable de la gestion des données et des opérations
liées aux étudiants, telles que l'ajout, la mise à jour et la récupération des dossiers des
étudiants.
School Microservice
Le microservice School gère les données et les opérations liées à l'école, notamment
l'ajout, la mise à jour et l'extraction des dossiers scolaires.
90
Architecture microservices [Micro Services | Spring boot 3 | Spring Cloud]
91
Architecture microservices [Micro Services | Spring boot 3 | Spring Cloud]

Chapitre 01- Maitriser architecture micro-services avec Spring Boot et Spring Cloud-V2.pptx

  • 1.
    1 Architectures Micro-services avecSpring Boot et Spring Cloud Pr. Youness Abouqora Agile Project Manager and Cloud Solutions Architect y.abouqora@uhp.ac.ma 0661631552
  • 2.
    2 Plan 1. Introduction 2. Créationdes Microservices de Base 3. Service Discovery (Netflix eureka) 4. Gestion des routes Gateway (Api Gateway et Zuul Proxy) 5. Spring Cloud Config 6. Spring Consul Consul 7. Communications Synchrone entre Micro-services 8. Fault Tolerance using Resilience4j 9. Etude de cas pratique
  • 3.
    3 1. Introduction Applications Webclassiques : Architecture Monolithique  Volumineuses  Trop d’interdépendance entre les fichiers  S’exécutant sur un serveur en respectant l’architecture (requête - réponse)  Format de réponse : HTML, XML ou JSON
  • 4.
    4 1. Introduction Problématiques  Évolution Taille ↗ complexité ↗ ⇒  Après mise-à-jour : faut-il garder le code précédent ou le supprimer ?  Déploiement  Échec de déploiement toutes les briques de code sont remises en question ⇒ Une bonne maîtrise de tout le code est nécessaire pour la correction  Scalabilité : extensibilité sur plus de ressources  Verticale remplacer un serveur acceptant x nombre d’utilisateur par un autre ⇒ acceptant y nombre d’utilisateur (avec x < y) : √  Horizontale placer l’application sur plusieurs serveurs en parallèle : X ⇒
  • 5.
    5 1. Introduction Architecture MicroServices Diviser une application en plusieurs fragments intégralement autonomes  Chaque fragment a un objectif bien particulier  Un fragment est appelé Web Service  Un Web Service peut être utilisée  par notre application monolithique existante,  la partie serveur  la partie client  d’autres services Web.  Une Architecture MicroService (MSA) est implémentée par un ensemble de Web Service exposant une API REST  Le terme Microservice peut designer l’architecture ou un Web Service  L’architecture MSA permet de réaliser des applications Cloud-native : ce qui permet d’augmenter et de diminuer le nombre de ressources a la demande en fonction du besoin.
  • 6.
  • 7.
    7 1. Introduction MSA vsSOA (Service-Oriented Architecture)  Dans une MSA, un service s’occupe d’une fonctionnalité. Dans une SOA, un service s’occupe d’un domaine.  La taille des services dans une MSA < La taille des services dans une SOA.  Chaque Microservice possède sa propre base de données. Dans une SOA, une base de données est très souvent utilisée par plusieurs services.  Les SOA utilisent souvent SOAP. Les MSA privilégient REST.
  • 8.
    8 1. Introduction MSA :3 options pour les bases de données  Private-tables-per-service : chaque service possède un ensemble de tables accessibles uniquement via ce service.  Schema-per-service : chaque service possède un schéma de base de données prive pour ce service.  Database-server-per-service : chaque service possède son propre serveur de base de données Avantages d’une base de données par Microservice  Garantir l’autonomie des services et le couplage faible.  Chaque service peut utiliser le type de base de données le mieux adapté à ses besoins.
  • 9.
    2. Création desMicroservices de Base Getting Started with Spring Boot: Spring Initializr https://start.spring.io 9
  • 10.
    10 2. Création desMicroservices de Base Premier microservice • Aller dans File > New > Project • Chosir Spring Initializr • Saisir : - micro-service-personne dans Name, - com.example dans Group, - micro-service-personne dans Artifact - com.example.demo dans Package Cliquer sur Next Chercher et cocher les cases correspondantes aux Spring Data JPA, MySQL Driver, Lombok, Spring Web, Spring Boot DevTools et Eureka Discovery Client Cliquer sur Next puis sur Finish
  • 11.
    11 2. Création desMicroservices de Base Explication  Le package contenant le point d’entrée de notre application (la classe contenant le puclic static void main) est com.example.demo  Tous les autres packages dao, model... doivent être dans le package demo. Pour la suite, nous considérons  une entité Personne à définir dans com.example.demo.model  une interface DAO PersonneRepository à définir dans com.example.demo.dao  un controleur REST PersonneController à définir dans com.example.demo.controller
  • 12.
    © Achref EL MOUELHI © Créons uneentité Personne dans com.example.demo.model package com.example.demo.model; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.NonNull; import lombok.RequiredArgsConstructor; @NoArgsConstructor @AllArgsConstructor @Data @Entity @RequiredArgsConstructor public class Personne { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long num; @NonNull private String nom; @NonNull private String prenom; } H & H: Research and Training 2. Création des Microservices de Base
  • 13.
    © Achref EL MOUELHI © Preparons notreinterface DAO PersonneRepository package com.example.demo.dao; import org.springframework.data.jpa.repository.JpaRepository; import com.example.demo.model.Personne; public interface PersonneRepository extends JpaRepository<Personne, Long> { } H & H: Research and Training 2. Création des Microservices de Base
  • 14.
    © Achref EL MOUELHI © Cre´ons lecontroˆ leur REST suivant @RestController @AllArgsConstructor public class PersonneRestControl ler { private PersonneRepository personneRepository; @GetMapping("/personnes") public List<Personne> getPersonnes() { return personneRepository.findAll(); } @GetMapping("/personnes/{id}") public Personne getPersonne(@PathVariable("id") long id) { return personneRepository.findById(id).orElse(null); } @PostMapping("/personnes") public Personne addPersonne(@RequestBody Personne personne) { return personneRepository.save(personne); } H & H: Research and Training 2. Création des Microservices de Base
  • 15.
    EL MOUELHI © Dans application.properties, ajoutonsles données permettant la connexion à la base de données et la configuration de Hibernate server.servlet.contextpath=/ws server.port=8081 spring.datasource.url = jdbc:mysql://localhost:3306/mic roservice_personne? createDatabaseIfNotExist=true spring.datasource.username = root spring.datasource.password = spring.jpa.hibernate.ddl-auto = create-drop spring.jpa.show-sql = true spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQLDialect spring.jpa.hibernate.naming.physical- strategy = org.hibernate.boot.model.naming. PhysicalNamingStrategyStandardImpl L’ajout de la propriété spring.jpa.hibernate.naming.physical-strategy permet de forcer Hibernate à utiliser les mêmes noms pour les tables et les colonnes que les entités et les attributs. H & H: Research and Training 2. Création des Microservices de Base
  • 16.
    H & H:Research and Training 16 / 45 Dans application.properties, définissons un nom pour notre application spring.application.name=PERSONNE-SERVICE Pour commencer, on ne publie pas le microservice spring.cloud.discovery.enabled=false 2. Création des Microservices de Base
  • 17.
    © Achref EL MOUELHI © Commençons parmodifier le point d’entree (qui implementera l’interface ApplicationRunner) pour alimenter la base de donne´es avec quelques données de test @SpringBootApplication public class MicroServicePersonneApplication { public static void main(String[] args) { SpringApplication.run(MicroServicePersonneApplication.class, args); } @Bean ApplicationRunner start(PersonneRepository repository) { return args -> { repository.save(new Personne("El", "chama")); repository.save(new Personne("Abouqora", "Youness")); }; } } H & H: Research and Training 2. Création des Microservices de Base
  • 18.
    Spring Boot Pour tester http://localhost:8081/ws/personnes Ouhttp://localhost:8081/ws/personnes/1 2. Création des Microservices de Base
  • 19.
    Aller dans File> New > Project Chercher Spring, dans Spring Boot sélectionner Spring initializr et cliquer sur Next > Saisir micro-service-adresse dans Name, com.example dans Group, micro-service-adresse dans Artifact com.example.demo dans Package Cliquer sur Next Chercher et cocher les cases correspondantes aux Spring Data JPA, MySQL Driver, Lombok, Spring Web, Spring Boot DevTools, Eureka Discovery Client et OpenFeign Cliquer sur Next puis sur Finish H & H: Research and Training 19 / 45 2. Création des Microservices de Base
  • 20.
    • Explication Le packagecontenant le point d’entrée de notre application (la classe contenant le puclic static void main) est com.example.demo Tous les autres packages dao, model... doivent être dans le package demo. une entité com.example.demo.daoAdresse à définir dans com.example.demo.model une interface DAO AdresseRepository à définir dans com.example.demo.dao un contrôleur REST AdresseController à définir dans H & H: Research and Training 2. Création des Microservices de Base
  • 21.
    © Achref EL MOUELHI © Créons uneentité Adresse dans com.example.demo.model package com.example.demo.model; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.NonNull; import lombok.RequiredArgsConstructor; @NoArgsConstructor @AllArgsConstructor @RequiredArgsConstructor @Data @Entity public class Adresse { @Id @GeneratedValue(strate gy = GenerationType.IDE NTITY) private Long id; @NonNull private String rue; @NonNull private String codePostal; @NonNull private String ville; } H & H: Research and Training 21 / 45 2. Création des Microservices de Base
  • 22.
    © Achref EL MOUELHI © Comme cemicroservice ne persiste pas les personnes, on va creer une classe Personne (qui n’a pas l’annotation @Entity) dans com.example.demo.model package com.example.demo.model; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.NonNull; import lombok.RequiredArgsConstructor; @NoArgsConstructor @AllArgsConstructor @Data @RequiredArgsConstructor public class Personne { private Long num; @NonNull private String nom; @NonNull private String prenom; } H & H: Research and Training 2. Création des Microservices de Base
  • 23.
    © Achref EL MOUELHI © Modifions l’entiteAdresse en ajoutant l’association avec Personne dans @NoArgsConstructor @AllArgsConstructor @RequiredArgsConstructor @Data @Entity public class Adresse { @Id @GeneratedValue(strate gy = GenerationType.IDE NTITY) private Long id; @NonNull private String rue; @NonNull private String codePostal; @NonNull private String ville; @NonNull private Long idPersonne; @Transient private Personne personne; } H & H: Research and Training 2. Création des Microservices de Base
  • 24.
    © Achref EL MOUELHI © Preparons notreinterface DAO AdresseRepository package com.example.demo.dao; import org.springframework.data.jpa.repository.JpaRepository; import com.example.demo.model.Adresse; public interface AdresseRepository extends JpaRepository<Adresse, Long> { } H & H: Research and Training 24 / 45 2. Création des Microservices de Base
  • 25.
    EL MOUELHI © Dans application.properties, ajoutonsles données permettant la connexion à la base de données et la configuration de Hibernate server.servlet.context-path=/ws server.port=8082 spring.datasource.url = jdbc:mysql://localhost:3306/micr oservice_adresse? createDatabaseIfNotExist=true spring.datasource.username = root spring.datasource.password = root spring.jpa.hibernate.ddl-auto = create-drop spring.jpa.show-sql = true spring.jpa.properties.hibernate. dialect = org.hibernate.dialect.MySQLDiale ct spring.jpa.hibernate.naming.phys ical-strategy = org.hibernate.boot.model.naming. PhysicalNamingStrategyStandardIm pl # microservice spring.application.name=ADRESSE-SERVICE spring.cloud.discovery.enabled=false L’ajout de la propriété spring.jpa.hibernate.naming.physical-strategy permet de forcer Hibernate à utiliser les meˆmes noms pour les tables et les colonnes que les entités et les attributs. H & H: Research and Training 2. Création des Microservices de Base
  • 26.
    © Achref EL MOUELHI © Commenc¸ onspar modifier le point d’entrée (qui implémentera l’interface ApplicationRunner) pour alimenter la base de donne´es avec quelques donne´es de test @SpringBootApplication public class MicroServiceAdresseApplication { public static void main(String[] args) { SpringApplication.run(MicroServiceAdresseApplication.class, args); } @Bean ApplicationRunner start(AdresseRepository repository) { return args -> { repository.save(new Adresse("prado", "13008", "Marseille", 1L)); repository.save(new Adresse("plantes", "75014", "Paris", 2L)); }; } } H & H: Research and Training 26 / 45 2. Création des Microservices de Base
  • 27.
    H & H:Research and Training 27 / 45 2. Création des Microservices de Base Pour activer Open Feign, ajoutons l’annotation @EnableFeignClients à la classe de démarrage @EnableFeignClients @SpringBootApplication public class MicroServiceAdresseApp lication { public static void main(String[] args) { SpringApplication.run(MicroServiceAdresseApplication.class, args); } @Bean ApplicationRunner start(AdresseRepository repository) { return args -> { repository.save(new Adresse("49 Av. Lalla aicha", "20000", "Rabat", 1L)); repository.save(new Adresse("380 Bd Brahim Roudani", "10000", "Casablanca", 2L)); }; } }
  • 28.
    Créons une interfacecliente PersonneRestClient qui va assurer la communication avec le premier microservice package com.example.demo.openfeign; import java.util.List; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import com.example.demo.model.Personne; @FeignClient(name = "PERSONNE-SERVICE") public interface PersonneRestClient { @GetMapping("/ws/personnes") public List<Personne> getPersonnes(); @GetMapping("/ws/personnes/ {id}") public Personne getPersonne(@PathVariable("id") H & H: Research and Training 2. Création des Microservices de Base- OpenFeign
  • 29.
    H & H:Research and Training 29 / 45 Créons un contrôleur REST AdresseRestController dans lequel nous injectons AdresseRepository @RestController @AllArgsConstructor public class AdresseRestControll er { private AdresseReposito ry adresseReposito ry; 2. Création des Microservices de Base
  • 30.
    Pour lier lesadresses aux personnes, injectons aussi PersonneRestClient @RestController @AllArgsConstructor public class AdresseRestControll er { private PersonneRestClient personneRestClient; private AdresseRepository adresseRepository; } H & H: Research and Training 2. Création des Microservices de Base
  • 31.
    © Achref EL MOUELHI © Ajoutons maintenantles trois actions suivantes @GetMapping("/adresses") public List<Adresse> getAdresses() { var adresses = adresseRepository.findAll(); for (Adresse a : adresses) { a.setPersonne(personneRestClient.getPerson ne(a.getIdPersonne())); } return adresses; } @GetMapping("/adresses/{id}") public Adresse getAdresse(@PathVariable("id") long id) { var a = adresseRepository.findById(id).orElse(null); a.setPersonne(personneRestClient.getPersonne(a.getIdPerso nne())); return a; } @PostMapping("/adresses") public Adresse addAdresse(@RequestBody Adresse adresse) { return adresseRepository.save(adresse); } H & H: Research and Training 2. Création des Microservices de Base
  • 32.
    32 Démarrer l’application Vérifier, dansla console, que les tuples de la classes de démarrage ont été insérés Faire une requête GET à http://localhost:8082/ws/adresses lance une exception car les microservices ne sont pas déclarés H & H: Research and Training 34 / 45 2. Création des Microservices de Base
  • 33.
    33 Démarrer l’application Vérifier, dansla console, que les tuples de la classes de démarrage ont été insérés Faire une requête GET à http://localhost:8082/ws/adresses lance une exception car les microservices ne sont pas déclarés Pour résoudre le probleme précédent Il faut créer un projet Eureka Discovery (Spring Cloud). H & H: Research and Training 34 / 45 3. Service Discovery (netflix eureka)
  • 34.
    34 H & H:Research and Training 34 / 45 3. Service Discovery (netflix eureka)
  • 35.
    Aller dans File> New > Other Chercher Spring, dans Spring Boot sélectionner Spring Starter Project et cli- quer sur Next > Saisir eureka-service dans Name, com.example dans Group, eureka-service dans Artifact com.example.demo dans Package Cliquer sur Next Chercher et cocher les cases correspondantes a ` Eureka Server et DevTools H & H: Research and Training 3. Service Discovery (netflix eureka)
  • 36.
    © Achref EL MOUELHI © Commenc¸ onspar activer Eureka Server dans la classe de demarrage package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server. EnableEurekaServer; @SpringBootApplication @EnableEurekaServer public class EurekaServiceApplicati on { public static void main(String[] args) { SpringApplication.run(EurekaServiceApplication.class, args); } } H & H: Research and Training 3. Service Discovery (netflix eureka)
  • 37.
    37 Les propriétés àajouter dans application.properties server.port=8761 eureka.client.fetch-registry=false eureka.client.register-with- eureka=false 8761 : nume´ro de port par de´faut d’Eureka eureka.client.fetch-registry=false : pour ne pas enregistrer le serveur en tant que client eureka.client.register-with-eureka=false : pour ne pas l’enregistrer dans le registre des services H & H: Research and Training 37 / 45 3. Service Discovery (netflix eureka) Explication
  • 38.
    38 Dans application.properties demicro-service-personne et micro-service-adresse, mettons la propriété suivante à true spring.cloud.discovery.enabled=true Pour tester 1 démarrer le projet eureka-service 2 3 H & H: Research and Training 38 / 45 démarrer le projet micro-service-personne démarrer le projet micro-service-adresse 3. Service Discovery (netflix eureka)
  • 39.
    H & H:Research and Training Allez à http://localhost:8082/ws/adresses et vérifiez qu’on récupère les adresses avec les personnes [ { "id": 1, "rue": "paradis", "codePostal": "13006", "ville": "Rabat", "idPersonne": 1, "personne": { "num": 1, "nom": "El", "prenom": "Chama" } }, { " i d " : 2 , "rue": "plantes", "codePostal": "75014", "ville": "Casablanca", "idPersonne": 2, "personne": { "num": 2, 3. Service Discovery (netflix eureka)
  • 40.
    Remarque 1 2 H & H:Research and Training 40 / 45 Allez à http://localhost:8761/ Vérifiez la présence de deux services dans Instances currently registered with Eureka 3. Service Discovery (netflix eureka)
  • 41.
    41 H & H:Research and Training 41 / 45 4. Passerelle de services (Api Gateway) Constat Chaque microservice a sa propre URL : host + port + ... Comment utiliser la même URL avec un path unique pour chaque microservice? Utiliser le routage dynamique avec le Gateway
  • 42.
    42 4. Passerelle deservices (Api Gateway) Explication Une passerelle de services sert d'intermédiaire entre un service et le client qui l'appelle. Le client ne parle qu'à une seule URL gérée par la passerelle de services. La passerelle de services distingue le chemin provenant de l'appel du client et détermine le service que le client tente d'invoquer. exemples de problèmes transversaux pouvant être implémentés dans une passerelle de services incluent : - Routage statique - Routage dynamique - Authentification et autorisation - Collecte et journalisation des métriques
  • 43.
    H & H:Research and Training 43 / 45 Aller dans File > New > Project Chercher Spring, dans Spring Boot sélectionner Spring Initializr et cli quer sur Next > Saisir gateway-routing dans Name, com.example dans Group, gateway-routing dans Artifact com.example.demo dans Package Cliquer sur Next Chercher et cocher les cases correspondantes aux Reactive Gateway, DevTools et Eureka Discovery Client Cliquer sur Next puis sur Finish 4. Gestion des routes Gateway : Routage dynamique
  • 44.
    © Achref EL MOUELHI © Spring Boot Ajoutonsle bean suivant dans la classe de démarrage pour activer et utiliser le routage dynamique package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.ReactiveDiscoveryClient; import org.springframework.cloud.gateway.discovery.DiscoveryClientRouteDefinitionL ocator; import org.springframework.cloud.gateway.discovery.DiscoveryLocatorProperties; import org.springframework.context.annotation.Bean; @SpringBootApplication public class GatewayRoutingApplication { public static void main(String[] args) { SpringApplication.run(GatewayRoutingApplication.class, args); } @Bean DiscoveryClientRouteDefinitionLocator dynamicRoute( ReactiveDiscoveryClient rdc, DiscoveryLocatorProperties dlp) { return new DiscoveryClientRouteDefinitionLocator(rdc, dlp); } } H & H: Research and Training 44 / 45 4. Gestion des routes Gateway : Routage dynamique
  • 45.
    EL H & H:Research and Training 45 / 45 Les propriétés à ajouter dans application.properties server.port=8080 spring.application.name=GATEWAY spring.cloud.discovery.enabled=true eureka.instance.prefer-ip-address=true 4. Gestion des routes Gateway : Routage dynamique
  • 46.
    46 Spring Boot Ordre delancement des projets 1 2 3 4 H & H: Research and Training 45 / 45 démarrer le projet eureka-service démarrer le projet micro-service-personne démarrer le projet micro-service-adresse démarrer le projet gateway 4. Gestion des routes Gateway : Routage dynamique Pour tester Pour récupérer la liste d’adresses : http://localhost:8080/ADRESSE-SERVICE/ws/adresses Pour récupérer la liste de personnes : http://localhost:8080/PERSONNE-SERVICE/ws/personnes
  • 47.
    47 5. Spring CloudConfig Explication Dans une architecture microservices, plusieurs services s'exécutent en même temps, sur des processus différents, avec chacun sa propre configuration et ses propres paramètres. Spring Cloud Config fournit un support côté serveur et côté client pour externaliser les configurations dans un système distribué. Grâce au service de configuration, il est possible d'avoir un endroit centralisé pour gérer les propriétés de chacun de ces services. -
  • 48.
    Aller dans File> New > Project Chercher Spring, dans Spring Boot sélectionner Spring Initializr et cli quer sur Next > Saisir config-service dans Name, com.example dans Group, config-service dans Artifact com.example.demo dans Package Cliquer sur Next Chercher et cocher les cases correspondantes Config Server et DevTools Cliquer sur Next H & H: Research and Training 5. Spring Cloud Config
  • 49.
    © Achref EL MOUELHI © Commençons paractiver Eureka Server dans la classe de démarrage package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server. EnableEurekaServer; @SpringBootApplication @EnableConfigServer public class EurekaServiceApplicati on { public static void main(String[] args) { SpringApplication.run(EurekaServiceApplication.class, args); } } H & H: Research and Training 5. Spring Cloud Config
  • 50.
    50 37 / 45 Lespropriétés à ajouter dans application.properties server.port=8888 spring.cloud.config.server.git.uri=file://$ {user.home}/cloud-config spring.cloud.config.server.git.default-label=main 5. Spring Cloud Config Création du repository git : cloud-config Lancer git bash : - cd C: - cd Users/Youness Abouqora - mkdir cloud-config - cd cloud-config - ls - git init
  • 51.
    51 37 / 45 5.Spring Cloud Config Creation du repository git : cloud-config Lancer git bash : cd C: cd Users/Youness Abouqora cd cloud-config code application.properties Le fichier application.properties contient tout les parametres de configurations qui sont commun a tout les microservices. Lancer git bash : cd C:/ cd Users/Youness Abouqora cd cloud-config git status git add . git commit –m "first commit" Creation du repository git : cloud-config
  • 52.
    52 37 / 45 5.Spring Cloud Config Le répertoire de configuration doit être un répertoire git. Pour cela: Ouvrir le terminal avec IntelliJ et naviguer vers ce répertoire. Initialiser votre répertoire: git init Créer une entrée racine dans le repository: git add . Faire un commit: git commit -m "bien ajoutee" Creation du repository git : cloud-config Les propriétés à ajouter dans application.properties server.port=8888 spring.cloud.config.server.git.uri=file:./src/mai n/resources/cloud-config Créer le répertoire config-cloud à l'arborescence src/main/resources Créer dans ce répertoire le fichier application.properties dans lequel vous insérez l'instruction suivante: Ce fichier sera partagé entre tous les microservices utilisant ce service de configuration. global=xxxxx
  • 53.
    53 37 / 45 Ajouterla dependance spring-cloud-starter-config dans le microservices personne-service, adresse-service, eureka-service et gateway-service <dependency> <groupId> org.springframework.cloud </groupId> <artifactId> spring-cloud-starter-config </artifactId> </dependency> 5. Spring Cloud Config Les propriétés à ajouter dans application.properties de MS personne- service spring.application.name=PERSONNE-SERVICE spring.config.import=optional:configserver:http:/ /localhost:8888/
  • 54.
    54 5. Spring CloudConfig Pour tester le MS personne-service configuration: http://http://localhost:8888/personne-service/master
  • 55.
    55 6. Spring CloudConsul Explication Consul fournit un support de premier ordre pour la découverte de services, la vérification de l'état de santé, le stockage K/V et les centres de données multiples. Consul.io Agent consul Serveur Consul Service des adresses Service des personnes ■ Agent consulaire • Bilan de santé • Demandes de renseignements ■ Serveur Consul • Données du magasin • Répondre aux questions • Élection du chef de file (Leader Election)
  • 56.
    56 6. Spring CloudConsul Configuration Service Registration Service Discovery Consul Spring Boot Application Spring Cloud Consul Service Health Contrôle Déploiement Configuration • Mise à jour en cours d'exécution • Pas de configuration locale • Découverte dynamique des points d'extrémité • L'ordre de départ n'a pas d'importance • Un déploiement simple • Séparation des environnements • Découvrir les services à surveiller • La santé du service est plus importante que la santé d'une seule instance.
  • 57.
    H & H:Research and Training 57 / 45 6. Spring Cloud Consul Download et install consul.io Ouvrez l’invite du commande dans le rep d’installation et lancez la commande : consul.exe agent -dev https://developer.hashicorp.com/consul/install
  • 58.
    58 6. Spring CloudConsul Allez à http://localhost:8500/
  • 59.
    59 37 / 45 Ajouterla dependance spring-cloud-starter-consul-discovery dans le microservices personne-service, adresse-service et gateway-service <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-consul- discovery</artifactId> </dependency> 5. Spring Cloud Consul Les propriétés à ajouter dans application.properties de MS personne- service spring.cloud.consul.port=8500 spring.cloud.consul.host=localhost spring.cloud.consul.discovery=PERSONNE-SERVICE
  • 60.
    H & H:Research and Training 60 / 45 6. Spring Cloud Consul/configuration distribuée Download et install consul.io Ouvrez l’invite du commande dans le rep d’installation et lancez la commande : consul.exe agent -dev https://developer.hashicorp.com/consul/install
  • 61.
    Dans application.yaml, ajoutonsles données permettant la configuration du cunsul et importation des key-value store spring: application: name: PERSONNE-SERVICE config: import:"optional:consul:localhost:8500" cloud: consul: host: localhost port: 8500 discovery: PERSONNE-SERVICE config: format: YAML prefix: config default-context: personne-service data-key: data H & H: Research and Training 6. Spring Cloud Consul/configuration distribuée Ajouter la configuration suivante dans le key-value store de Consul db: url: jdbc:mysql://localhost:3306/personne-service? createDatabaseIfNotExist=true username: root password: root
  • 62.
    Dans application.yaml, ajoutonsles données permettant la connexion à la base de données et la configuration de Hibernate datasource: url: ${db.url} username: ${db.username} password: ${db.password} jpa: hibernate: ddl-auto: create-drop naming: physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingSt rategyStandardImpl show-sql: true properties: hibernate: format_sql: true server: port: 8081 servlet: context-path: /api H & H: Research and Training 6. Spring Cloud Consul/configuration distribuée
  • 63.
    63 7. Communications Synchroneentre Micro-services - RestTemplate RestTemplate RestTemplate est un client synchrone fourni par Spring Framework pour effectuer des requêtes HTTP. Il simplifie l'interaction avec les services web RESTful en fournissant des méthodes pour diverses opérations HTTP, telles que GET, POST, PUT, DELETE, etc. Ce client dispose de plusieurs méthodes, telles que getForObject(), getForEntity(), exchange() @Bean public RestTemplate APIRestTemplate(RestTemplateBuilder builder) { return builder.rootUri("http://localhost:8081/api").build(); } Personne personne = restTemplate.getForObject("/personnes/{id}", Personne.class,1); logger.info("Personnes trouvée: {}", personne); Map<String, Object> parameters = Map.of("id", 1); ResponseEntity<Personne> entity = restTemplate.getForEntity("/personnes/{id}", Personne.class, parameters); logger.info("Personnes trouvée: {}", entity.getBody()); logger.info("headers trouvée: {}: {}", entity.getHeaders()); Retrieving data
  • 64.
    64 7. Communications Synchroneentre Micro-services - RestTemplate Personne request = new Personne("Rami", "Said"); Product personne = restTemplate.postForObject("/personnes", request, Personne.class); logger.info("Created product: {}", personne); Personne request = new Personne(“Rami“,”Said”); HttpEntity<Personne> httpEntity = new HttpEntity<>(request, null); RequestEntity<Personne> entity = restTemplate.exchange("/personnes/1", HttpMethod.PUT, httpEntity, Personne.class); logger.info("Updated personne: {}", entity.getBody()); Send data
  • 65.
    65 7. Communications Synchroneentre Micro-services - RestTemplate @Service public class AdresseService { @Autowired private AdresseRepository adresseRepository; @Autowired private RestTemplate restTemplate; private final String URL = "http://localhost:8081/SERVICE-PERSONNE"; public List<AdresseResponse> findAllAdresses() { List<Adresse> adresses = adresseRepository.findAll(); ResponseEntity<Personne[]> response = restTemplate.getForEntity(this.URL + "/api/personnes", Personne[].class); Personne[] personnes= response.getBody(); return personnes.stream().map((Adresse adresse) -> mapToAdresseResponse(adresse, personnes)).toList(); } } // this function allow the change the Car Entity to A Model that we will send ot the client side using the @Builder Annotation private Adresse Response mapToAdresseResponse (Adresse adresse, Personne[] personnes) { Personne foundPersonne = Arrays.stream(personnes) .filter(personne -> personne.getId().equals(adresse.getIdPersonne())) .findFirst() .orElse(null); return AdresseResponse.builder() .id(adresse.getId()) .rue(adresse.getRue()) .personne(foundPersonne) .codePostal(adresse.getCodePostal()) .ville(adresse.getVille()) .build(); } Créons un Service AdresseService dans lequel nous injectons les fonctions suivantes
  • 66.
    66 7. Communications Synchroneentre Micro-services - RestTemplate // this function allow the change the Car Entity to A Model that we will send ot the client side using the @Builder Annotation private Adresse Response mapToAdresseResponse (Adresse adresse, Personne[] personnes) { Personne foundPersonne = Arrays.stream(personnes) .filter(personne -> personne.getId().equals(adresse.getIdPersonne())) .findFirst() .orElse(null); return AdresseResponse.builder() .id(adresse.getId()) .rue(adresse.getRue()) .personne(foundPersonne) .codePostal(adresse.getCodePostal()) .ville(adresse.getVille()) .build(); } public AdresseResponse findById(Long id) throws Exception { Adresse adresse = adresseRepository.findById(id).orElseThrow(() -> new Exception("Invalid Car Id")); Client client = restTemplate.getForObject(this.URL + "/api/pers/" + adresse.getIdPersonne(), Personne.class); return AdresseResponse.builder() .id(adresse.getId()) .rue(adresse.getRue()) .personne(foundPersonne) .codePostal(adresse.getCodePostal()) .ville(adresse.getVille()) .build(); }
  • 67.
    67 37 / 45 5.Communications Synchrone entre Micro-services - RestTemplate Ajouter la calsse PersonneRestTemplate dans le MS Adresse-service @Service public class PersonneRestTemplate { private final RestTemplate restTemplate; @Autowired public PersonneRestTemplate(RestTemplateBuilder builder) { this.restTemplate = builder .rootUri("http://localhost:8081") .build(); } } Dans PersonneRestTemplate, ajoutons la methode getAdressesDetails et un Bean private PersonneRestTemplate personneRestTemplate; @GetMapping("/adressesDet/{id}") public ResponseEntity<AdresseResponse> getAdressesDetails(@PathVariable("id") long id){ AdresseResponse adresse= adresseService.getAdresseById(id); return ResponseEntity.status(HttpStatus.OK).body(adresse); }
  • 68.
    68 7. Programmation reactive- WebFlux WebClient Contrairement au modèle bloquant du framework Spring MVC, Spring WebClient est conçu pour traiter un grand nombre de requêtes simultanément, avec une faible latence et un débit élevé. Il fournit un modèle de programmation réactive, qui permet au framework de traiter les demandes comme des flux d'événements, plutôt que comme des demandes individuelles. Constat RestTemplate est intrinsèquement bloquant, ce qui n'est pas idéal pour les systèmes réactifs modernes à hautes performances, où les E/S non bloquantes peuvent offrir une meilleure évolutivité et une meilleure réactivité. Par conséquent, WebClient a été introduit en tant qu'alternative moderne et non bloquante.
  • 69.
    69 7. Communications Synchroneentre Micro-services - WebClient Ajouter la dependance spring-cloud-starter-webFlux dans le microservices adresse-service <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifa ctId> </dependency> WebClient webClient = WebClient.create() ; // Avec un URI vide WebClient webClient = WebClient.create("http://localhost:8081/api") ; // Avec l'URI racine spécifié La méthode create() est une méthode surchargée et peut éventuellement accepter une URL de base pour les requêtes.
  • 70.
    70 7. Communications Synchroneentre Micro-services - WebClient @Configuration @PropertySource("classpath:application.properties") public class AppConfiguration { @Value("${personneService.base.url}") private String personneBaseUrl; @Bean public ModelMapper modelMapperBean(){ return new ModelMapper(); } @Bean public WebClient webClient(){ return WebClient .builder() .baseUrl(personneBaseUrl) .defaultCookie("cookie-name", "cookie-value") .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .build(); } } Créons une classe AppConfiguration Ajouter la configuration suivante dans le application.properties personneService.base.url=http://localhost:8081/api
  • 71.
    Dans AdresseService, ajoutonsla methode getAdresseById(long id) H & H: Research and Training 6. Communications Synchrone entre Micro-services - WebClient public AdresseResponse getAdresseById(long id){ Optional<Adresse> adresse = adresseRepository.findById(id); AdresseResponse adresseResponse= mapper.map(adresse, AdresseResponse.class); PersonneResponse personneResponse= webClient.get() .uri("/personnes/{id}",adresseResponse.getIdPersonne()) .retrieve() .bodyToMono(PersonneResponse.class) .block(); adresseResponse.setPersonne(personneResponse); return adresseResponse; } Dans AdresseController, ajoutons la methode getAdressesDetails et un Bean private AdresseService adresseService; @GetMapping("/adressesDet/{id}") public ResponseEntity<AdresseResponse> getAdressesDetails(@PathVariable("id") long id){ AdresseResponse adresse= adresseService.getAdresseById(id); return ResponseEntity.status(HttpStatus.OK).body(adresse); }
  • 72.
    Dans AdresseService, ajoutonsla methode getAdresseById(long id) H & H: Research and Training 6. Communications Synchrone entre Micro-services - WebClient public AdresseResponse getAdresseById(long id){ Optional<Adresse> adresse = adresseRepository.findById(id); AdresseResponse adresseResponse= mapper.map(adresse, AdresseResponse.class); PersonneResponse personneResponse= webClient.get() .uri("/personnes/{id}",adresseResponse.getIdPersonne()) .retrieve() .bodyToMono(PersonneResponse.class) .block(); adresseResponse.setPersonne(personneResponse); return adresseResponse; } Dans AdresseController, ajoutons la methode getAdressesDetails et un Bean private AdresseService adresseService; @GetMapping("/adressesDet/{id}") public ResponseEntity<AdresseResponse> getAdressesDetails(@PathVariable("id") long id){ AdresseResponse adresse= adresseService.getAdresseById(id); return ResponseEntity.status(HttpStatus.OK).body(adresse); }
  • 73.
    73 7. Communications Synchroneentre Micro-services - WebClient @Bean public WebClient APIWebClient(WebClient.Builder builder builder) { return builder.baseUri("http://localhost:8081/api").build(); } Mono<Product> personneMono = webClient .get() .uri(builder -> builder .path("/personnes/1") .build()) .retrieve() .bodyToMono(Personne.class); productMono.subscribe(product -> logger.info("Found product: {}", product)); webClient .get() .uri(builder -> builder .pathSegment("products", "{id}") // Add a URL variable .build(Map.of("id", 1))) // Map each URL variable .retrieve() .bodyToMono(Product.class) .subscribe(product -> logger.info("Found product: {}", product)); Retrieving data
  • 74.
    74 7. Communications Synchroneentre Micro-services - WebClient CreateProductRequest request = new CreateProductRequest("Banana"); webClient .post() .uri("/products/add") .bodyValue(request) .retrieve() .bodyToMono(Product.class) .subscribe(product -> logger.info("Created product: {}", product)); UpdateProductRequest request = new UpdateProductRequest("Bananaaaaa"); webClient .put() .uri("/products/101") .bodyValue(request) .retrieve() .bodyToMono(Product.class) .subscribe(product -> logger.info("Updated product: {}", product)); Send data
  • 75.
    75 7. Fault Toleranceusing Resilience4j Introduction Dans un contexte de microservices, il est courant de rencontrer des déviations lors de son fonctionnement en temps réel. Cela peut se manifester par des temps de réponse prolongés, des problèmes de réseau, des échecs d'appels REST, ou encore des surcharges dues à un volume élevé de requêtes, parmi d'autres complications. Pour gérer ces types d'erreurs potentielles, il est essentiel d'intégrer un mécanisme de tolérance aux pannes dans notre application. À cette fin, nous nous appuierons sur la bibliothèque Resilience4j. resilience4j.io
  • 76.
    76 7. Fault Toleranceusing Resilience4j Resilience4j Resilience4j is a lightweight, easy-to-use fault tolerance library inspired by Netflix Hystrix, but designed for Java 8 and functional programming resilience4j.io Design pattern Les patterns de résilience des clients sont axés sur la protection d'un client de ladite ressource (un autre appel de microservice ou une base de données) en cas de défaillance de la ressource distante. Le but de ces modèles est de permettre au client d'échouer rapidement (Fail-fast), de ne pas consommer de ressources, telles que les connexions de base de données et les pools de threads, et d'empêcher le problème du service distant de se propager « en amont » aux consommateurs du client. • Bulkhead : limit the number of concurrent requests within a particular period. Limits concurrent executions • TimeLimiter : the process of setting a time limit for a Microservice to respond limit duration of execution • Rate Limiter : limits the number of incoming requests for a given period. Limit executions/period • Circuit Breaker: is a pattern in developing the Microservices based applications in order to tolerate any fault. Temporary blocks possible failures • Retry : retries failed service calls to increase the chance of getting response. repeats failed executions
  • 77.
    77 7. Fault Toleranceusing Resilience4j- Design pattern Bulkhead Ratelimiter B ne pouvant encaisser plus de X appels sur une durée, on va limiter le nombre d’appels sur une période donnée et rejeter les autres appels plutôt que les traiter et crasher A droite, on a limité à 2 appels concurrents de B (qui est lent) pour éviter de saturer les threads de traitement de B qui est limité en ressources Annotation resilience4j : @Bulkhead(name=BULKHEAD_NAME) Annotation resilience4j : @RateLimiter(name=RATELIMITER_NAME)
  • 78.
    78 7. Fault Toleranceusing Resilience4j- Design pattern Timelimiter La méthode B a mis trop de temps à renvoyer un résultat. Circuit breaker Gérer la latence et les échecs des webservices utilisés par votre application Retry Le premier appel à B a échoué et le second a renvoyé un succès Annotation resilience4j : @Retry(name=RETRY_NAME) Annotation resilience4j : @Timelimiter(name=TIMELIMITER_NAME) Annotation resilience4j : @CircuitBreaker(name=CIRCUIT_BREAKER_NAME)
  • 79.
    79 37 / 45 Ajouterles dependances spring-cloud-starter-actuator, spring- cloud-starter-circuitbreaker-resilience4j dans le microservice adresse-service <dependency> <groupId>org.springframework.boot</ groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</ groupId> <artifactId>spring-cloud-starter-circuitbreaker- resilience4j</artifactId> </dependency> 7. Fault Tolerance using Resilience4j- Config
  • 80.
    80 37 / 45 5.Actuator Les propriétés à ajouter dans application.properties de MS adresse- service management: health: ## active circuit breaker circuitbreakers: enabled: true endpoints: web: exposure: include: health endpoint: health: show-details: always
  • 81.
    81 37 / 45 Lespropriétés à ajouter dans application.yaml pour circuitbreaker resilience4j: circuitbreaker: configs: default // instances: // adresseService: registerHealthIndicator: true eventConsumerBufferSize: 10 failureRateThreshold: 50 #indicates that if 50% of requests are getting failed, open the circuit ie. Make the Circuit Breaker state as Open. minimumNumberOfCalls: 5 #indicates that we need at least 5 calls to calculate the failure rate threshold. automaticTransitionFromOpenToHalfOpenEnabled: true #indicates that don’t switch directly from the open state to the closed state, consider the half-open state also. waitDurationInOpenState: 3s #indicates the waiting time interval while switching from the open state to the closed state. permittedNumberOfCallsInHalfOpenState: 3 #indicates that when on half-open state, consider sending 4 requests. If 80% of them are failing, switch circuit breaker to open state. slidingWindowSize: 10 #indicates that if 80% of requests out of 10 (it means 8) are failing, open the circuit. sliding-window-type: count_based # indicates that we are using COUNT_BASED sliding window. Another type is TIME_BASED. 7. Fault Tolerance using Resilience4j- config
  • 82.
    Ajoutons maintenant les l’annotation @CircuitBreakeret la methode getDefaultAdress() public static final String ADRESSE_SERVICE="adresseService"; @GetMapping("/adresses") @CircuitBreaker(name=“default”, fallbackMethod = "getDefaultAdresses") public List<Adresse> getAdresses() { var adresses = adresseRepository.findAll(); for (Adresse a : adresses) { a.setPersonne(personneRestClient.getPersonne(a.getId Personne())); } return adresses; } @GetMapping("/adresses/{id}") @CircuitBreaker(name=ADRESSE_SERVICE, fallbackMethod = "getDefaultAdress") public Adresse getAdresse(@PathVariable("id") long id) { var a = adresseRepository.findById(id).orElse(null); a.setPersonne(personneRestClient.getPersonne(a.getIdPersonne())); return a; } @PostMapping("/adresses") public Adresse addAdresse(@RequestBody Adresse adresse) { return adresseRepository.save(adresse); } public List<Adresse> getDefaultAdresses(Exception e){ return Stream.of( Adresse.builder() .rue("rue inconue") .codePostal("code inconue") .ville("ville inconue") .idPersonne(0L) .personne(null) .build() ).collect(Collectors.toList()); H & H: Research and Training 7. Fault Tolerance using Resilience4j- Config
  • 83.
    83 37 / 45 Lespropriétés à ajouter dans application.yaml pour retry resilience4j: retry: instances: adresseService: max-attempts: 5 wait-duration: 5s 7. Fault Tolerance using Resilience4j- Config Ajoutons maintenant dans AdresseController les l’annotation @RateLimiter @Retry(name = ADRESSE_SERVICE, fallbackMethod = "getMessageFallBack") et la methode getMessageFallBack() public String getInvoiceFallback(Exception e) { log.info("---RESPONSE FROM FALLBACK METHOD---"); return "SERVICE IS DOWN, PLEASE TRY AFTER SOMETIME !!!"; } Une fois les 5 tentatives terminées, vous devriez voir le message « -RESPONSE DE LA MÉTHODE DE RETOUR- » dans la console. Ce message indique que la méthode de secours a été appelée.
  • 84.
    84 37 / 45 Lespropriétés à ajouter dans application.yaml pour ratelimiter resilience4j: ratelimiter: instances: adresseService: limitForPeriod: 2 limitRefreshPeriod: 15s registerHealthIndicator: true 7. Fault Tolerance using Resilience4j- Config Ajoutons maintenant dans AdresseController les l’annotation @RateLimiter @RateLimiter(name = ADRESSE_SERVICE) et la methode getMessageFallBack() public ResponseEntity<String> getMessageFallBack(RequestNotPermitted exception) { return ResponseEntity.status(HttpStatus.TOO_MANY_REQUESTS) .body("Too many requests : No further request will be accepted. Please try after sometime"); } Une fois que vous avez actualisé plus de 2 fois en l'espace de 3 secondes, vous devriez voir apparaître le message « Too many requests : No further request will be accepted. Please try after sometime »
  • 85.
    85 37 / 45 Lespropriétés à ajouter dans application.yaml pour bulkhead resilience4j: bulkhead: instances: adresseService: max-concurrent-calls: 5 #indicates that if the number of concurrent calls exceed 5, activate the fallback method. max-wait-duration: 0 #indicates that don’t wait for anything, show response immediately based on the configuration. server: tomcat: threads: max: 5 7. Fault Tolerance using Resilience4j- config Ajoutons maintenant dans AdresseController les l’annotation @Bulkhead @Bulkhead(name = ADRESSE_SERVICE) public List<Adresse> getAdresses(){ … try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } … return adresses; }
  • 86.
    86 37 / 45 Lespropriétés à ajouter dans application.yaml pour timelimiter resilience4j.timelimiter: configs: default: limitForPeriod: 2 limitRefreshPeriod: 15s timeoutDuration: 5s registerHealthIndicator: true eventConsumerBufferSize: 100 instances: backendA: baseConfig: default backendB: baseConfig: default limitForPeriod: 3 7. Fault Tolerance using Resilience4j- default Config resilience4j: timelimiter: instances: adresseService: timeout-duration: 1ms #indicates that the maximum amount of time a request can take to respond is 1 millisecond cancel-running-future: false #indicates that do not cancel the Running Completable Futures After TimeOut. Ajoutons maintenant dans AdresseController l’annotation @TimeLimiter @Timelimiter(name = ADRESSE_SERVICE) à ajouter egalement dans application.yaml pour default configs
  • 87.
    87 37 / 45 Lespropriétés à ajouter dans application.yaml pour timelimiter resilience4j.timelimiter: configs: default: limitForPeriod: 2 limitRefreshPeriod: 15s timeoutDuration: 5s registerHealthIndicator: true eventConsumerBufferSize: 100 instances: backendA: baseConfig: default backendB: baseConfig: default limitForPeriod: 3 7. Tester avec JMeter resilience4j: timelimiter: instances: adresseService: timeout-duration: 1ms #indicates that the maximum amount of time a request can take to respond is 1 millisecond cancel-running-future: false #indicates that do not cancel the Running Completable Futures After TimeOut. Ajoutons maintenant dans AdresseController l’annotation @TimeLimiter @Timelimiter(name = ADRESSE_SERVICE) à ajouter egalement dans application.yaml pour default configs
  • 88.
    88 Etude de caspratique : Mise en oeuvre d’une architecture microservices [Micro Services | Spring boot 3 | Spring Cloud
  • 89.
    89 Etude de caspratique : Mise en oeuvre d’une architecture microservices [Micro Services | Spring boot 3 | Spring Cloud API Gateway Le passerelle API sert de point d'entrée unique pour toutes les demandes des clients, en les gérant et en les acheminant vers les microservices approprié Config Server Le serveur de configuration centralise la gestion de la configuration pour tous les microservices, ce qui simplifie la maintenance des applications et la cohérence entre les environnements. Discovery Server Le serveur de découverte assure l'enregistrement et la découverte des services, ce qui permet une communication transparente entre les services au sein de l'écosystème de microservices Student Microservice Le microservice Student est responsable de la gestion des données et des opérations liées aux étudiants, telles que l'ajout, la mise à jour et la récupération des dossiers des étudiants. School Microservice Le microservice School gère les données et les opérations liées à l'école, notamment l'ajout, la mise à jour et l'extraction des dossiers scolaires.
  • 90.
    90 Architecture microservices [MicroServices | Spring boot 3 | Spring Cloud]
  • 91.
    91 Architecture microservices [MicroServices | Spring boot 3 | Spring Cloud]