Académique Documents
Professionnel Documents
Culture Documents
le FrameWork SpringBoot
1
L’architecture micro-services a été inventée pour résoudre certaines des difficultés causées par les gros projets.
Avec le temps, les projets informatiques ont tendance à grossir : on étend petit à petit les fonctionnalités existantes, on en ajoute d’autres, et
on supprime rarement les anciennes.
En même temps que le code et le projet s’étendent, un certain nombre de douleurs apparaissent :
Complexité
Quand la quantité de code augmente, le code devient de plus en plus complexe. Même avec une architecture logicielle solide, les
interdépendances entre les différentes briques augmentent avec le temps.
Évolutivité et fiabilité
• Plus le temps passe, plus les nouvelles fonctionnalités métier deviennent complexes, et plus les différentes briques ont d’interactions. On
a beau organiser le code en couches et en composants, il y a toujours des cas particuliers et des rustines qui rendent les choses plus
floues.
• Au-delà d’un certain seuil, il devient impossible d’avoir en tête un modèle global du projet.
• Même avec une base de tests solide, la multiplication des effets de bord de chaque action rend le système moins fiable, et il devient alors
plus difficile d’ajouter proprement des nouvelles fonctionnalités et d’effectuer des « refactorings ».
« Scalabilité » horizontale
• Améliorer la « scalabilité » d’un système peut demander de modifier des éléments structurants du projet.
• Plus un projet est gros, plus ces interventions deviennent coûteuses et risquées.
• Le risque est alors de se retrouver avec un système qu’il est impossible de faire évoluer pour un nouveau cas d’usage.
2
Innovation
Innovation technologique
• Pour capitaliser les investissements et faciliter la gestion des personnes, il est normal de vouloir avoir une cohérence
entre les différents projets d’une entreprise : même manière de travailler, mêmes langages de programmation, mêmes
outils.
• Chaque projet est invité à suivre des choix transverses, et peut s’en écarter en fonction de ses spécificités, à condition de
le justifier.
• Pour les gros projets, la même tension a lieu à l’intérieur même des projets : pour éviter la fragmentation, chaque
évolution technique doit pouvoir être propagée à l’intégralité du code.
• Avec le temps, les modifications deviennent donc plus coûteuses, et il est plus difficile d’introduire de nouveaux outils
pour des besoins spécifiques.
Innovation métier
• Pour répondre aux nouveaux besoins métier, il faut être capable de ménager une zone d’innovation à l’intérieur des
projets.
• Car si certaines nouveautés sont mises en œuvre par de nouveaux projets, la plupart se font sur des projets existants.
• Or plus un projet est gros, plus il est critique pour l’entreprise, moins on va prendre de risques de le modifier pour tester
de nouveaux produits ou de nouveaux marchés, et petit à petit les enjeux de stabilité vont prendre le pas sur la capacité
d’innovation.
3
« Le découpage se fait par domaine métier, en groupant les
services et les types de données qui ont des liens forts, et en
séparant quand ils sont suffisamment indépendants. »
4
Les avantages de l’approche micro-services
Complexité
Évolutivité et fiabilité
Contraindre la taille limite les cas particuliers, et permet d’avoir en tête l’intégralité des comportements.
La dette technique est gardée sous contrôle, et le code est ainsi capable d’évoluer. Passer par des appels de services pour communiquer avec
les autres domaines formalise les échanges.
Les contrats d’interface sont alors plus carrés, et il est plus facile de prendre en compte tous les cas, y compris les cas d’erreurs.
Scalabilité horizontale
Avec des applications d’une taille limitée, il est plus facile d’augmenter la « scalabilité » en « refactorant » le code ou en la réécrivant
complètement en fonction des nouveaux besoins.
Innovation
Innovation technologique
Les bases de codes et les équipes sont indépendantes et peuvent donc faire leurs choix techniques en fonction de leurs besoins propres.
Innovation métier
Si tout le système d’information est structuré en services, il est facile d’expérimenter en démarrant un nouveau projet s’appuyant sur 5les
données des autres, et plus facile de décomissionner car c’est l’ensemble d’un projet qui sera supprimé.
Parler Micro-Services c’est bien, en faire c’est mieux
Les Micro-Services ont cette fâcheuse tendance à faire parler les gens plutôt qu'à les faire coder.
Il faut dire qu'à l'époque SOA (il y a 5-10 ans donc), il fallait faire avec SOAP, les ESB (EAI « rebrandés »); il valait
mieux en parler qu’en faire.
Mais maintenant tout n’a pas changé mais nous avons enfin les technologies nous permettant de mettre en place
l’ensemble des architectures/solutions rêvées il y a quelques années (Relisez :
http://shop.oreilly.com/product/9780596006754.do ), le livre a plus de 10 ans, si c’est pas du MicroServices, ça y
ressemble.
6
L’approche Micro-Services avec SpringBoot
7
Spring Boot est un projet ou un micro framework qui a notamment pour but de faciliter la configuration
d’un projet Spring et de réduire le temps alloué au démarrage d’un projet.
Pour arriver à remplir cet objectif, Spring Boot se base sur plusieurs éléments :
•Une génération rapide de la structure de votre projet en y incluant toutes les dépendances Maven
nécessaires à votre application.
Par exemple si vous voulez ajouter toutes les dépendances pour gérer la sécurité il suffit d’ajouter le starter « spring-boot-
starter-security ».
8
•L’auto-configuration, qui applique une configuration par défaut au démarrage de votre application
pour toutes dépendances présentes dans celle-ci.
•Cette configuration s’active à partir du moment où vous avez annoté votre application avec
« @EnableAutoConfiguration » ou « @SpringBootApplication ».
•Bien entendu cette configuration peut-être surchargée via des propriétés Spring prédéfinie ou via une
configuration Java.
•L’auto-configuration simplifie la configuration sans pour autant vous restreindre dans les
fonctionnalités de Spring.
Par exemple, si vous utilisez le starter « spring-boot-starter-security », Spring Boot vous configurera la sécurité dans votre
application avec notamment un utilisateur par défaut et un mot de passe généré aléatoirement au démarrage de votre
application.
9
• En plus de ces premiers éléments qui facilitent la configuration d’un projet, Spring Boot offre d’autres
avantages notamment en termes de déploiement applicatif.
• Habituellement, le déploiement d’une application JEE nécessite la génération d’un fichier .war qui doit
être déployé sur un serveur comme un Apache Tomcat.
Spring Boot simplifie ce mécanisme en offrant la possibilité d’intégrer directement un serveur Tomcat
dans votre exécutable. Au lancement de celui-ci, un Tomcat embarqué sera démarré afin de faire
fonctionner votre application.
• Enfin, Spring Boot met à disposition des opérationnels, des métriques qu’ils peuvent suivre une fois
l’application déployée en production. Pour cela Spring Boot utilise « Actuator » qui est un système qui
permet de monitorer une application via des URLs spécifiques ou des commandes disponibles via SSH
« CraSH ». Vous avez toujours la possibilité de monitorer également vos services avec JMX.
10
• Accélérer le développement d’applications JEE
• Auto-Configuration
• StandAlone application
• Déploiement simplifié
11
Technologies supportées
12
13
Prérequis indispensable
Installer le jdk 8 dans sa dernière version
http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html
echo %JAVA_HOME%
echo %PATH%
14
Prérequis +/- indispensable
Installer NetBeans 8.2 pour JEE https://netbeans.org/downloads/
Essentiellement pour la prise en charge du HTML et JavaScript
15
Prérequis +/- indispensable
Installer le plugin NetBeans pour SpringBoot Ce plugins propose la création d’un projet Maven Spring Boot simplifié)
NB Spring Boot version 1.5
16
Prérequis indispensable
installer Maven version 3.5.0
https://maven.apache.org/download.cgi
Ajouter le chemin
C:\apache-maven-3.5.0-bin\apache-maven-3.5.0\bin
Dans la variable PATH
Tester l’installation et la version
17
Backend MicroService via WS REST et AMQP
3
Microservice
Avec persistence
Des données
Message amqp
Message amqp
Service Backend
AMQP
1 Consommateur
18
Créer un premier package Maven Basic SpringBoot 1
Sous NetBeans :
File | New Project | Maven | Spring Boot basic project
19
1 Refactorisation du projet :
Nom du projet(1) , chemin du package(2), nom du fichier principal Java (3)
(Clic droit + renommer ou clic droit + Refactor + Renommer)
20
Créer un premier package Maven SpringBoot Initializr
Sous NetBeans :
File | New Project | Maven | Spring Boot Initializr project
21
Vous pouvez également créer votre projet via le site Spring InitialiZr
https://start.spring.io/
22
1
Ajouter les dépendances complémentaires au projet (spring-boot-starter-web)
Clic droit sur « dependencies » de notre projet
23
1
Ajouter la dépendance amqp RabbitMQ client amqp-client
24
1 Accéder au fichier pom.xml sous NetBeans
Vous accédez au fichier pom via le menu contextuel sur la zone de projet NetBeans, menu « Open POM »
<groupId>com.ht.dev</groupId>
<artifactId>PremierMicroService</artifactId>
<version>0.0.1</version>
<packaging>jar</packaging>
<name>PremierMicroService</name>
<description>Basic project for Spring
Boot</description>
25
Exemple de code source qui permet de mettre en place 3 web services REST et un Producteur pour rabbitMQ. 1
package com.ht.dev;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
//@SpringBootApplication
@Controller
@EnableAutoConfiguration
@SpringBootConfiguration
public class PremierMicroService {
@RequestMapping("/message")
@ResponseBody
String message() throws TimeoutException {
String QUEUE_NAME = "hello";
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
String message = "Salut les licences 3 alt!";
try
{
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
channel.basicPublish("", QUEUE_NAME, null, message.getBytes("UTF-8"));
channel.close();
}
catch (IOException ex) {
return ex.getMessage();
}
return " [x] Envoyé '" + message + "'";
}
27
@RequestMapping(value="/message/{msg}", method=RequestMethod.GET) 1
@ResponseBody
String messageMsg(@PathVariable("msg") String msg) throws TimeoutException {
String QUEUE_NAME = "hello";
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
try
{
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.close();
}
catch (IOException ex) {
return ex.getMessage();
}
return " [x] Envoyé '" + msg + "'";
}
} //fin de programme
28
désactiver "Compile on Save" avant de compiler et exécuter le projet sous NetBeans
Clic droit sur le projet, puis menu « Properties »
29
cmd /c "\"\"C:\\Program Files\\NetBeans 8.2\\java\\maven\\bin\\mvn.bat\" -Drun.jvmArguments=\"-noverify -XX:TieredStopAtLevel=1 -Xms64m\" -
Drun.mainClass=com.example.BasicApplication -Dmaven.ext.class.path=\"C:\\Program Files\\NetBeans 8.2\\java\\maven-nblib\\netbeans-eventspy.jar\" -Dfile.encoding=UTF-8
spring-boot:run\""
Scanning for projects...
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v1.5.2.RELEASE)
2017-05-07 00:08:52.493 INFO 8764 --- [ main] com.ht.dev.PremierMicroService : Starting PremierMicroService on PC104160 with PID 8764
(C:\TEMP\PremierMicroservice\target\classes started by tondeur-h in C:\TEMP\PremierMicroservice)
2017-05-07 00:08:52.493 INFO 8764 --- [ main] com.ht.dev.PremierMicroService : No active profile set, falling back to default profiles: default
2017-05-07 00:08:52.540 INFO 8764 --- [ main] ationConfigEmbeddedWebApplicationContext : Refreshing
org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@13eb8acf: startup date [Sun May 07 00:08:52 CEST 2017]; root of context hierarchy
2017-05-07 00:08:53.601 INFO 8764 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http)
2017-05-07 00:08:53.601 INFO 8764 --- [ main] o.apache.catalina.core.StandardService : Starting service Tomcat
2017-05-07 00:08:53.601 INFO 8764 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.11
2017-05-07 00:08:53.679 INFO 8764 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2017-05-07 00:08:53.679 INFO 8764 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1155 ms
2017-05-07 00:08:53.804 INFO 8764 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Mapping servlet: 'dispatcherServlet' to [/]
2017-05-07 00:08:53.804 INFO 8764 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*]
2017-05-07 00:08:53.804 INFO 8764 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2017-05-07 00:08:53.804 INFO 8764 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*]
2017-05-07 00:08:53.804 INFO 8764 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*]
2017-05-07 00:08:54.006 INFO 8764 --- [ main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice:
org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@13eb8acf: startup date [Sun May 07 00:08:52 CEST 2017]; root of context hierarchy
2017-05-07 00:08:54.038 INFO 8764 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/message]}" onto java.lang.String
com.ht.dev.PremierMicroService.message() throws java.util.concurrent.TimeoutException
2017-05-07 00:08:54.038 INFO 8764 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/hello]}" onto java.lang.String
com.ht.dev.PremierMicroService.home()
2017-05-07 00:08:54.038 INFO 8764 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public
org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>>
org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2017-05-07 00:08:54.038 INFO 8764 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public
org.springframework.web.servlet.ModelAndView
org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2017-05-07 00:08:54.069 INFO 8764 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class
org.springframework.web.servlet.resource.ResourceHttpRequestHandler] 30
2017-05-07 00:08:54.069 INFO 8764 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class
org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-05-07 00:08:54.100 INFO 8764 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class
Tester les web service avec un browser
http://localhost:8080/hello
http://localhost:8080/message
http://localhost:8080/message/Bonjour le monde du microservice
31
Compiler et packager avec Maven
Se rendre dans le dossier du projet ou se trouve le fichier pom.xml et lancer la commande Maven :
mvn package
Se rendre ensuite dans le dossier Target ou a été généré notre package Jar
32
Lancer le microService avec la commande Maven
mvn spring-boot:run
OU JAVA
java –jar basic-0.0.1-SNAPSHOT.jar
33
Exécution du consommateur
34
Backend MicroService via WS REST et AMQP
3
Microservice
Avec persistence
Des données
Message amqp
Message amqp
Service Backend
AMQP
1 Consommateur
35
1 Ajouter un appel supplémentaire de Web service (au service Backend) à notre projet PremierMicroService
public class PremierMicroService {
//return backendServiceURL;
return reponse.getReponse();
}
36
1 Classe POJO BackEndDTO Placer les paramètre du WS dans le fichier
Application.properties
37
2 Création du service Backend BackendMicroService
package com.ht.dev;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
@SpringBootApplication
@Controller
public class BackendMicroService {
package com.ht.dev;
class Reponse{
String reponse;
39
2
Avant de lancer le microService BackendMicroService, ne pas oublier de spécifier le port 8081 pour le
démarrage de ce service.
On va spécifier cette valeur de port dans le fichier application.properties
server.port=8081
40
Monitorer vos microServices avec JMX
Par défaut Spring Boot active les objets JMX dans son code, ce qui permet de monitorer vos microservices avec
l’outils « Java Mission Control » jmc.exe qui se trouve dans le bin du JDK.
41
Monitorer vos microServices avec Spring Boot Starter Actuator 1.5.3
Insérer la dépendance suivant dans votre projet, ceci permet d’ajouter des Web Services à votre application
<dependency> Placer dans le fichier de config application.properties
<groupId>org.springframework.boot</groupId> management.security.enabled=false
<artifactId>spring-boot-starter-actuator</artifactId>
<version>1.5.3.RELEASE</version>
</dependency>
Example : le EndPoint http://localhost:8080/env ressemblera à :
• http://localhost:8080/beans
• http://localhost:8080/env
• http://localhost:8080/health
• http://localhost:8080/metrics
• http://localhost:8080/trace
• http://localhost:8080/mappings
42
Codecentric a développé une UI intéressante que l’on peut cloner à partir de GitHub.
https://github.com/codecentric/spring-boot-admin
43
Backend MicroService via WS REST et AMQP
3
Microservice
Avec persistence
Des données
Message amqp
Message amqp
Service Backend
AMQP
1 Consommateur
44
package com.ht.dev; Couche Persistance avec JDBCTemplate
3
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Créer un nouveau projet et ajouter les
import org.springframework.beans.factory.annotation.Autowired; Dépendance ci-dessous
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@SpringBootApplication
@Controller
public class BackendJDBCMicroService implements CommandLineRunner{
@Autowired
JdbcTemplate jdbcTemplate;
@RequestMapping("/name/{NOM}/fname/{PRENOM}")
@ResponseBody
public String Insert_Person(@PathVariable("NOM") String nom, @PathVariable("PRENOM") String prenom){
jdbcTemplate.update("INSERT INTO APP.persons(first_name, last_name) VALUES (?,?)", nom, prenom);
return "Insertion "+nom+" "+prenom+" ok";
} 45
3
@Override
public void run(String... strings) {
log.info("Creation de la table");
try {
//jdbcTemplate.execute("DROP TABLE persons");
jdbcTemplate.execute("CREATE TABLE APP.persons(id INTEGER, first_name VARCHAR(255), last_name VARCHAR(255))");
}
catch(DataAccessException e) {}
}
46
3 Classe qui va servir de rowMapper lors des Query
package com.ht.dev;
@Override
public String toString() {
return String.format(
"Person[id=%d, firstName='%s', lastName='%s']",id, firstName,
lastName);
}
47
Avant de lancer le microService BackendJDBCMicroService, ne pas oublier de spécifier les données d’accés à la
base de données Java Derby embedded.
On va spécifier ces valeurs dans le fichier application.properties
spring.datasource.driver-class-name=org.apache.derby.jdbc.EmbeddedDriver
spring.datasource.url=jdbc:derby:backendJDBCMicroService;create=true
spring.datasource.username=bjms
spring.datasource.password=bjms
48
3 Requêter dans la base de données
49
Exemple d’une réponse HTTP et d’un corps au format JSON
@RequestMapping(value="/arnum/{cle}/IPP={IPP}",method = RequestMethod.GET)
private ResponseEntity<List<Patient>> getByName(@PathVariable("cle") String cle,@PathVariable(« IPP") String
IPP)
{
50
Notions MVC avec Spring Boot
Chaque projet développé en MVC, doit principalement présenter une classe Controller (dispatcher), une ou des
classes métiers pour les accès aux ressources, et des Template écrit en HTML et ThymeLeaf.
On utilisera la classe Model qui permettra de faire la liaison entre notre controller et les Template.
51
package com.ht.dev.testms;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan; Déclaration d’une application SpringBoot
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
Dispatcher de l’appel de la
@SpringBootApplication page Web ./bonjour en type
@Controller Déclaration de la classe controller POST
@ComponentScan
public class TestMsApplication {
@RequestMapping (value="/bonjour",method=RequestMethod.POST)
private String bonjour(@RequestParam(name="nom", required=false, defaultValue="Hervé") String nom,
Model model)
{
model.addAttribute("nom", nom); Utilisation de la classe Model pour l’appel
return "bonjour";
du Template HTML « bonjour.html » Mapping de la variable
}
nom transmis par le
public static void main(String[] args) { protocole POST avec la
SpringApplication.run(TestMsApplication.class, args); variable locale nom
}
}
52
Exemple de Template ThymeLeaf (page bonjour.html)
<!DOCTYPE html>
<html>
<head>
<title>Page Bonjour</title>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
</head>
<body>
<div>
<p th:text="'Bonjour '+${nom}+', bienvenue sur cette page'"/>
</div>
</body>
</html>
53
Discovery Service : Eureka
dans une architecture AMS, le focus doit être fait non seulement sur le découpage des services mais aussi
et surtout sur les interactions entre ces services.
Il sera nécessaire d’éviter d'appeler un service directement via sa localisation (même si elle est configurée selon la
plateforme cible de déploiement).
Par exemple, évitez d'utiliser l'url: http[s]://[host]:[port]/[nameservice] afin ne pas créer un couplage
fort entre les services.
On mettra donc en place dans notre MS un service de Discovery.
C’est le client qui s'enregistre dans le "Service Discovery". L'inconvénient de cette approche est de coder cette
partie dans chaque service client. Mais avec l'API Spring la tâche est plus simple.
54
55
Discovery Service Exemple
Serveur NetFlix
Eureka
discovery
1 1
Créer un nouveau projet SpringInitializr et insérer la dépendance Maven « Eureka discovery » et « Eureka Server »
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
<version>1.3.0.RELEASE</version>
</dependency>
57
La classe DemoApplication est générée et annotée avec @SpringBootApplication de Spring-Boot, nous
l'annotons également avec @EnableEurekaServer de spring-cloud
(package org.springframework.cloud.netflix.eureka.server.EnableEurekaServer).
Faisant cela, nous avons utilisé la brique de Netflix nommée Eureka qui est un "service discovery ou
service registry".
L'annotation @EnableEurekaServer est "side server", fournie par l'api spring-cloud pour faciliter la mise
en place de la découverte du service Eureka.
58
Tester le service Eureka
Il suffit d'exécuter le projet mvn clean package spring-boot:run puis de saisir dans le browser
l'url localhost:8761 pour voir s'afficher la page du service Eureka.
A ce stade aucune instance de micro-service n'est enregistrée d'où la mention "No instances available".
59
Service Discovery Client (client side)
•Créer un second projet spring-boot définissant le micro-service qui sera déployé dans le serveur
Eureka.
•Ecrire un RestController pour illustrer les notions de consommation de services via leurs noms
enregistrés dans "Eureka Registry".
60
Créer un nouveau projet SpringInitializr et insérer la dépendance Maven « Eureka discovery »
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
61
Configurer le Client BackEnd Eureka
spring.application.name=back
server.port=8081
eureka.client.fetchRegistry=true
eureka.client.registerWithEureka=true
eureka.client.useDnsForFetchingServiceUrls=false
instance.metadataMap.instanceId=${spring.application.name}:${server.port}
62
Controller Rest de l’application BackEnd
package com.dev.ht.clientbackdiscovery;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@RestController
@EnableEurekaClient
@RequestMapping({"/info","/"})
Mise à disposition d’un service
String info(){return ="Je suis la pages d'infos du back service";} info pour Eureka
@RequestMapping({"/bonjour"})
@ResponseBody
String bonjour(){return "Bonjour tout le monde!";}
63
Configurer le Client FrontEnd Eureka
spring.application.name=front
server.port=8090
eureka.client.fetchRegistry=true
eureka.client.registerWithEureka=true
eureka.client.useDnsForFetchingServiceUrls=false
eureka.client.eurekaServerDNSName=localhost
eureka.client.eurekaServerPort=8761
eureka.client.eurekaServerURLContext=eureka
instance.metadataMap.instanceId=${spring.application.name}:${server.port}
64
Controller Rest de l’application FrontEnd qui pourra appeler les services BackEnd
package com.dev.ht.clientfrontdiscovery;
@SpringBootApplication
@RestController import java.util.List;
@EnableEurekaClient import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.beans.factory.annotation.Autowired;
public class ClientfrontdiscoveryApplication { import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@Autowired import org.springframework.cloud.client.ServiceInstance;
private DiscoveryClient discoveryClient; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
public String serviceUrl() {
final StringBuilder sb=new StringBuilder();
List<ServiceInstance> instance = discoveryClient.getInstances("back");
instance.forEach(
si ->
{
sb.append ("Host= ");
sb.append(si.getHost());
sb.append(" Uri= ");
sb.append(si.getUri());
sb.append(" Port= ");
sb.append(si.getPort()); }
);
System.out.println("sb= "+sb.toString());
@RequestMapping("/discover")
public String index() {return serviceUrl();}
66
Circuit breaker, un pattern pour fiabiliser vos microservices (ou systèmes distribués)
Pour répondre à ces défis, la philosophie de « design for failure » (les traitements applicatifs doivent, dès leur conception,
prévoir le cas où les composants qu’ils appellent pourraient tomber en erreur) a pris encore plus d’importance.
67
Autres solutions
lift and shift Il suffit de prendre son application telle quelle et de la mettre sur le cloud sans faire de
modification (technique du lift and shift) => Utilisation de services en haute disponibilité & Utilisation
d’une infrastructure moderne => Cela n’est pas suffisant si l’application ne supporte pas la charge ou mal
développé (IP en fixe par exemple), le cloud peut couter cher également.
68
Design pattern : Timeout Il permet de ne pas attendre indéfiniment une
réponse en positionnant un temps d’attente
maximal=> L’erreur n’arrivera qu’après le temps
d’attente maximum (contraire au fail fast)=>
Consommation de ressource (connexion,
mémoire) inutile
69
Circuit Breaker
Le circuit breaker permet de contrôler la collaboration entre différents services afin d’offrir une grande tolérance à la latence
et à l’échec en fonction d’un certain nombre de critères d’erreur (timeout, nombre d’erreurs, élément dans la réponse), ce
pattern permet de désactiver l’envoi de requêtes au service appelé et de renvoyer plus rapidement une réponse alternative
de repli (fallback), aussi appelé graceful degradation.
Il agit comme un proxy implémentant une machine à états (Ouvert, Passant (fermé), Semi-ouvert) pour l’apprentissage de
l’état du service.
70
Lorsque le nombre d’échecs successifs dépasse un seuil, le circuit s’ouvre pour
ne plus laisser passer de requêtes. À ce moment-là, deux mécanismes se
déclenchent :
Une fois le seuil de passage à l’état semi-ouvert atteint (seuil du temps d’attente), le circuit breaker laisse à nouveau passer
quelques requêtes et passe dans l’état passant si tout se déroule bien.
Stocker toutes les requêtes en erreur avec le maximum de détail pour les traiter plus tard (AMQP / BDD)
Avoir plusieurs stratégies de réponse alternative en fonction du type d’erreur renvoyé par le service appelé (code “HTTP 503
Service Unavailable”, mauvaise réponse…)
Avoir des seuils intelligents qui s’adaptent après une période d’apprentissage
71
Graceful degradation
72
Hystrix
https://github.com/Netflix/hystrix/wiki
Hystrix est une API open source développée par Netflix qui implémente le pattern circuit
breaker.
Le but d’Hystrix est de rendre une application résiliente aux pannes de ses dépendances
externes en arrêtant momentanément de les invoquer le temps de leur indisponibilité. On
dit alors que Hystrix ouvre le circuit.
Comme Hystrix n’est pas averti de la reprise d’une dépendance tombée, il tente, à
intervalles réguliers, d’appeler cette dépendance.
Dès que cette dernière est rétablie, il ferme alors son circuit et tous les appels qu’il reçoit
sont transmis à cette dépendance.
73
Hystrix constitue un point d’accès unique à une dépendance externe. Il englobe (wrappe) les appels clients dans un objet
suivant le pattern Command. Concrètement, chaque appel distant est wrappé dans un objet HystrixCommand.
Hystrix fonctionne avec deux modes, thread et sémaphore :
Thread : Hystrix maintient son propre pool de threads. Un appel distant est exécuté par un thread Hystrix. Une fois que
tous les threads sont pris, les nouveaux appels arrivants sont rejetés.
Sémaphore : l’appel distant est exécuté par le même thread du client appelant. Une fois que le nombre de sémaphores
défini est atteint, tous les appels client sont rejetés. Ce mode est préconisé pour les appels courts.
Le mode thread est le mode par défaut d’Hystrix. Il tire son avantage par son isolation du pool de threads de l’appelant.
74
CHANGEMENT DE VITESSE
75
Les Microservices
ÉLASTIQUE
Un Microservice doit pouvoir être déployé un nombre de fois qui varie en fonction de la demande, et ce,
indépendamment des autres services dans la même application.
RÉSILENT
Un Microservice doit échouer sans affecter d'autres services dans la même application.
76
SOLUTIONS D'ORCHESTRATION OPENSOURCE
77