Architecture JEE et Spring en 2022
Architecture JEE et Spring en 2022
2021 — 2022
Table des matières
1 Introduction à JEE 4
1.1 Architecture JEE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.2 Services et Organisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.2.1 Services d’infrastructures . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.2.2 Services de communications . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.2.3 Serveur d’application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.2.4 Serveur d’objet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.2.5 Organisation et Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.3 Le patron de conception MVC et standards JEE . . . . . . . . . . . . . . . . . . . 6
1.3.1 Structure d’une application Java EE . . . . . . . . . . . . . . . . . . . . . 6
1.3.2 Le modèle MVC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2 JSF et JPA 10
2.1 Java Persistence API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.1.1 La couche ORM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.1.2 JPA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.1.3 Définition d’une entité JPA . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.1.4 Opérations sur les entités . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.1.5 Mise en relation d’entités . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.2 Java Server Faces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
2.2.1 Introduction aux Frameworks MVC . . . . . . . . . . . . . . . . . . . . . . 19
2.2.2 Introduction JSF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.2.3 Structure d’une application JSF . . . . . . . . . . . . . . . . . . . . . . . . 20
1
4.1.7 Spring Security . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
4.2 Spring boot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
4.2.1 Introduction Spring boot . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
4.2.2 Architecture de Spring Boot . . . . . . . . . . . . . . . . . . . . . . . . . . 42
4.2.3 Composants du projet Spring Boot . . . . . . . . . . . . . . . . . . . . . . 44
4.2.4 Spring Boot View : Thymeleaf . . . . . . . . . . . . . . . . . . . . . . . . 46
6 MicroServices 58
6.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
6.1.1 Principe de responsabilité unique . . . . . . . . . . . . . . . . . . . . . . . 59
6.1.2 Modélisé autour du domaine d’activité . . . . . . . . . . . . . . . . . . . . 59
6.1.3 Échec isolé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
6.1.4 Automatisation des infrastructures . . . . . . . . . . . . . . . . . . . . . . 59
6.1.5 Déployer indépendamment . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
6.2 Les défis de l’architecture des microservices . . . . . . . . . . . . . . . . . . . . . . 60
6.2.1 Contexte délimité . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
6.2.2 Augmentation et diminution dynamiques . . . . . . . . . . . . . . . . . . . 61
6.2.3 Surveillance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
6.2.4 Tolérance aux pannes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
6.2.5 Dépendance cyclique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
6.2.6 Culture DevOps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
6.3 Surveillance des microservices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
6.3.1 Outil de surveillance des microservices . . . . . . . . . . . . . . . . . . . . 63
6.4 Virtualisation des microservices . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
6.5 Composants des microservices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
6.5.1 Serveur de nommage Netflix Eureka . . . . . . . . . . . . . . . . . . . . . . 63
6.5.2 Serveur Hystrix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
6.5.3 Serveur de passerelle API Netflix Zuul . . . . . . . . . . . . . . . . . . . . 64
6.5.4 Ruban Netflix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
6.5.5 Serveur distribué Zipkin . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
6.6 Patrons de conception de microservices . . . . . . . . . . . . . . . . . . . . . . . . 64
6.6.1 Aggregator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
4
1.2 Services et Organisation
Dans le modèle, on trouve à la fois les données et les traitements à appliquer à ces données. Ce
bloc contient donc des objets Java d’une part, qui peuvent contenir des attributs (données) et
des méthodes (traitements) qui leur sont propres, et un système capable de stocker des données
d’autre part. Rien de bien transcendant ici, la complexité du code dépendra bien évidemment de
la complexité des traitements à effectuer par votre application.
Une page JSP est destinée à la vue. Elle est exécutée côté serveur et permet l’écriture de gabarits
(pages en langage "client" comme HTML, CSS, Javascript, XML, etc.). Elle permet au concep-
teur de la page d’appeler de manière transparente des portions de code Java, via des balises et
expressions ressemblant fortement aux balises de présentation HTML.
Une servlet est un objet qui permet d’intercepter les requêtes faites par un client, et qui peut
personnaliser une réponse en conséquence. Il fournit pour cela des méthodes permettant de
scruter les requêtes HTTP. Cet objet n’agit jamais directement sur les données, il faut le voir
comme un simple aiguilleur : il intercepte une requête issue d’un client, appelle éventuellement
des traitements effectués par le modèle, et ordonne en retour à la vue d’afficher le résultat au
client.
Pour bien faire, il nous faut une approche systématique. On peut par exemple décréter que :
— on crée une classe pour chaque entité ;
— on équipe cette classe avec des méthodes create(), get(), delete(), search(), ..., que l’on
implante en SQL/JDBC ;
— on implante la navigation d’une entité à une autre, à l’aide de requête SQL codées dans
les classes et exécutées en JDBC.
10
2.1.2 JPA
La Java Persistence API (abrégée en JPA), est une interface de programmation Java permettant
aux développeurs d’organiser desdonnées relationnelles dans des applications utilisant la plate-
forme Java.
La persistance dans ce contexte recouvre trois zones :
— l’API elle-même, définie dans le paquetage [Link].
— Le langage Java Persistence Query (JPQL).
— L’objet/les métadonnées relationnelles.
La Java Persistence API repose essentiellement sur l’utilisation des annotations, introduites dans
Java 5. Elles permettent de définir facilement des objets métier, qui pourront servir d’interface
entre la base de données et l’application, dans le cadre d’un mapping objet- relationnel.
L’annotation @ManyToOne :
ManyToOne
@ManyToOne
@JoinColumn (name="id_realisateur")
private Artiste realisateur;
public void setRealisateur(Artiste a) {realisateur = a;}
L’annotation @OneToMany :
OneToMany
@OneToMany
@JoinColumn(name="id_realisateur")
private Set<Film> filmsRealises = new HashSet<Film>();
public void addFilmsRealise(Film f) {[Link](f) ;}
public Set<Film> getFilmsRealises() {return filmsRealises;}
}
Associations bidirectionnelles :
Bidirectionnelles
@ManyToOne
@JoinColumn (name="id_realisateur")
private Artiste realisateur;
public void setRealisateur(Artiste a) {realisateur = a;}
public Artiste getRealisateur() {return realisateur;}
@OneToMany @JoinColumn(name="id_realisateur")
private Set<Film> filmsRealises = new HashSet<Film>();
public void addFilmsRealise(Film f) {[Link](f) ;}
public Set<Film> getFilmsRealises() {return filmsRealises;}
Associations plusieurs-à-plusieurs
Sans Attributs :
MayToMany
@ManyToMany()
@JoinTable(name = "Role", joinColumns = @JoinColumn(name = "id_film"),
inverseJoinColumns = @JoinColumn(name = "id_acteur"))
Set<Artiste> acteurs = new HashSet<Artiste>();
public Set<Artiste> getActeurs() {
return acteurs;
}
}
@ManyToMany(mappedBy = "acteurs")
Set<Film> filmo;
public Set<Film> getFilmo() {
Avec Attributs :
MayToMany
@ManyToMany()
@JoinTable(name = "Role", joinColumns = @JoinColumn(name = "id_film"),
inverseJoinColumns = @JoinColumn(name = "id_acteur"))
Set<Artiste> acteurs = new HashSet<Artiste>();
public Set<Artiste> getActeurs() {
return acteurs;
}
}
@ManyToMany(mappedBy = "acteurs")
Set<Film> filmo;
public Set<Film> getFilmo() {
return filmo;
}
MayToMany
import [Link].*;
@Embeddable
public class RoleId implements [Link] {
/** *
*/
private static final long serialVersionUID = 1L;
@ManyToOne
@JoinColumn(name = "id_acteur")
private Artiste acteur;
public Artiste getActeur() {
return acteur;
}
public void setActeur(Artiste a) {
[Link] = a;
L’héritage
@Entity
@Table(name = "ingenieur")
@PrimaryKeyJoinColumn(name = "id")
public class Ingenieur extends Employe {
private static final long serialVersionUID = 1L;
@Column(name = "statut")
private String statut;
@Column(name = "nb_projets")
private int nbProjets; }
@Entity
@Table(name = "technicien")
@PrimaryKeyJoinColumn(name = "id")
public class Technicien extends Employe {
private static final long serialVersionUID = 1L;
@Column(name = "poste")
private String poste;
@Column(name = "niveau")
private int niveau; }
@Entity
@Table(name = "ingenieur")
public class Ingenieur extends Employe {
private static final long serialVersionUID = 1L;
@Column(name = "statut")
private String statut;
@Column(name = "nb_projets")
@Entity
@Table(name = "technicien")
public class Technicien extends Employe {
private static final long serialVersionUID = 1L;
@Column(name = "poste")
private String poste;
@Column(name = "niveau")
private int niveau; }
@Entity
@Table(name = "ingenieur")
public class Ingenieur extends Employe {
private static final long serialVersionUID = 1L;
@Column(name = "statut")
private String statut;
@Column(name = "nb_projets")
private int nbProjets;
}
@Entity
@Table(name = "technicien")
public class Technicien extends Employe {
private static final long serialVersionUID = 1L;
@Column(name = "poste")
private String poste;
@Column(name = "niveau")
La spécification JPA décrit un langage de requête, appelé JPQL (Java Persistence Query Lan-
guage). Ce langage, reprend les fonctionnalités du SQL, et permet d’interroger une base de
données en utilisant les entités JPA définies dans une unité de persistance.
Une requête JPQL est donc écrite indépendamment de la base de données à laquelle elle s’adresse,
ce qui est un gain important de productivité.
Le langage JPQL définit trois types de requêtes :
— les requêtes de sélections.
— les requêtes de mise à jour.
— les requêtes d’effacement.
C’est le type de frameworks MVC le plus simple à comprendre et à assimiler par les développeurs
qui ont déjà de l’expérience avec le développement Java EE en suivant MVC, car il reprend
dans les grandes lignes sensiblement les mêmes principes. Ce sont des solutions qui interviennent
directement sur le cycle de vie d’une requête au sein de l’application (on rejoint ici cette histoire
de "prise de contrôle").
Solutions existants : Struts, Spring.
À la différence de ceux basés sur les requêtes, les frameworks basés sur les composants découpent
logiquement le code en "composants", masquant ainsi le chemin d’une requête au sein de l’appli-
cation. Ils essaient en quelque sorte d’abstraire les concepts de requête et réponse, et de traiter
une application comme une simple collection de composants qui présentent leur propre méthode
de rendu et des actions pour effectuer des tâches. Dans le MVC basé sur les composants, une
unique servlet jouant le rôle deFront Controllerva elle-même regrouper, convertir et valider les
paramètres de requête, et mettre à jour les valeurs du modèle. Le développeur n’a ainsi à se
soucier que des actions métier. La façon dont le contrôleur regroupe/convertit/valide/met à jour
les valeurs est définie dans un unique endroit, la vue. Puisque c’est impossible à réaliser à l’aide
de simple HTML "pur", un langage similaire spécifique est requis pour y parvenir. Dans le cas de
JSF, c’est un langage basé sur du XML (XHTML).
Solutions existants : JSF, Tapestry.
Des standards ont alors vu le jour. Le plus général est sans aucun doute Corba qui correspond
au modèle idéal des applications distribuées. Cependant, la lourdeur et la complexité de mise en
œuvre de ce genre d’applications sont les inconvénients majeurs de cette technologie, pour cette
raison Corba a été remplacé par le modèle EJB qui se base sur le protocole standard IIOP pour
l’échange de données.
La plate-forme Java EE propose de mettre en œuvre les couches métiers et persistance avec
les EJB. Particulièrement intéressants dans des environnements fortement distribués, jusqu’à la
version 3, leur mise en oeuvre est assez lourde sans l’utilisation d’outils tels que certains IDE ou
XDoclet.
La version 3 des EJB vise donc à simplifier le développement et la mise en oeuvre des EJB qui
sont fréquemment jugés trop complexes et trop lourds à mettre en oeuvre.
Cette nouvelle version majeure des EJB propose une simplification de leur développement tout
en conservant une compatibilité avec sa précédente version. Elle apporte de très nombreuses
22
fonctionnalités dans le but de simplifier la mise en oeuvre des EJB.
Les principales différences entre les EJB 2.x et EJB 3.0 sont donc :
Une classe POJO est une classe Java simple avec des méthodes Setter & Getter, mais elle n’est
ni implémentée ni étendue à partir d’une interface technologique spécifique ou d’une classe res-
pective.
Une interface Java qui ne s’étend pas à partir d’une interface spécifique à une technologie est
appelée POJI.
Les EJB Session se sont des composants distribuées qui implémentent les traitements du logique
métier. Ces composants sont accessible à distance via des protocoles RMI et IIOP.
Ils existent trois types d’EJB Session :
Stateless (sans état) : Les beans de type stateless sont les plus simples et les plus véloces car le
conteneur gère un pool d’instances qui sont utilisées au besoin, ce qui évite des opérations d’ins-
tanciation et de destruction à chaque utilisation. Ceci permet une meilleure montée en charge de
l’application.
— Pas d’état : on ne peut pas garder d’information dans les variables d’instance du bean
— Annotation : @Stateless
— Très souvent utilisé pour l’accès aux données
— Injection d’EntityManager (JPA) par @PersistenceContext
[Link]
@Stateless
public class ForumBean {
@PersistenceContext
EntityManager em;
Les EJB Session de type stateless peuvent utiliser les callbacks d’évènements marqués avec les
annotations suivantes :
— @PostConstruct
— @PreDestroy
Stateful (avec état) : Les beans de type Stateful sont capables de conserver leur état durant toute
leur utilisation par le client. Cet état n’est cependant pas persistant : les données sont perdues à
la fin de son utilisation ou à l’arrêt du serveur. Un exemple type d’utilisation de ce type de bean
est l’implémentation d’un caddie pour un site de vente en ligne.
@Remove
public void doOrder() {
// Sauve la commande dans la base de données
}
}
Les EJB session de type stateful peuvent utiliser les callbacks d’évènements marqués avec les
annotations suivantes :
— @PostConstruct
— @PostActivate
— @PreDestroy
— @PrePassivate
— @Remove
Le cycle de vie d’un Bean Session Stateful :
Les EJB entités représentent les données manipulées par l’application, chaque EJB entité est
associée à une table de la base de données, dans la version 3 des EJB l’accès au source de
données se fait souvent avec l’API JPA .
Les Beans des messages, un Listener qui permet de déclencher des traitements au niveau de
l’application suite à la réception d’un message asynchrone JMS.
[Link]
@MessageDriven(mappedName = "jms/TestQueue")
public class TestMessageDrivenBean implements MessageListener {
@Resource
MessageDrivenContext messageDrivenContext;
public void onMessage(Message message) {
try {
if (message instanceof TextMessage) {
TextMessage msg = (TextMessage) message;
[Link]();
}
} catch (JMSException e) {
[Link]();
} }
}
Permet de déclarer les méthodes qui sont accessible à distance par des composants qui sont
déployées dans d’autres machines, cette interface est représentée par @Remote. Un EJB sans
annotation locale ou remote est considéré comme local.
Permet de déclarer les méthodes qui sont accessible en local par des composants qui sont déployées
dans la même machine « même serveur d’application », cette interface est représentée par @Local.
En JSF
Entre beans
Pour appeler un EJB depuis une application cliente en utilise l’API JNDI.
JNDI ou Java Naming Directory Interface est un service d’annuaire qui permet la recherche de
ressources. Chaque ressource comme un EJB, une source de données ou une file d’attente JMS
s’exécutant sur un serveur d’applications reçoit un nom JNDI qui sera utilisé pour localiser la
ressource.
Pour cela l’EJB Session doit implémenter l’interface Remote pour activer l’accès à distance :
[Link]
Package [Link];
@Remote
public interface TestStatelessEjbRemote {
String sayHello(String name);
}
[Link]
public class TestEjbClient {
public static void main(String[] args) throws NamingException {
[Link](Context.INITIAL_CONTEXT_FACTORY, "[Link].
[Link]");
[Link](Context.URL_PKG_PREFIXES, "[Link]"
);
[Link](Context.PROVIDER_URL,"http-remoting://localhost:8080");
[Link]("[Link]",true);
Context context = new InitialContext(jndiProperties);
HelloEjbRemote helloTest = [Link]("ejb:/TestEjb/HelloTest!(
HelloEjbRemote) [Link]");
[Link]( [Link]("Test"));
}
@EJB(mappedName="java:global/CliEJB/HelloTest![Link]")
TestStatelessEjb testStatelessEjb;
public void doGet(HttpServletRequest request, HttpServletResponse response) {
[Link]("Stackify Reader");
}
}
Spring est effectivement un conteneur dit « léger », donc une infrastructure similaire à un serveur
d’application J2EE. Il prend donc en charge la création d’objets et la mise en relation d’objets par
l’intermédiaire d’un fichier de configuration dans la plupart des cas une fichier XML, récemment
remplacer par un autre mécanisme base sur les annotations qui décrit les objets à construire et
les relations de dépendances entre ces objets.
31
4.1.2 Architecture de la technologie Spring
Le framework est organisé en modules, reposant tous sur le module Spring Core :
La couche d’accès aux données / d’intégration comprend les modules JDBC, ORM, OXM, JMS
et Transaction dont les détails sont les suivants :
— JDBC : Le module JDBC fournit une couche d’abstraction JDBC qui élimine le besoin
de codage fastidieux lié à JDBC.
— ORM : Le module ORM fournit des couches d’intégration pour les API de mappage objet-
relationnel populaires, notamment JPA, JDO, Hibernate et iBatis.
— OXM :Le module OXM fournit une couche d’abstraction qui prend en charge les implé-
mentations de mappage Object / XML pour JAXB, Castor, XMLBeans, JiBX et XStream.
— JMS : Le module JMS du service de messagerie Java contient des fonctionnalités permet-
tant de générer et de consommer des messages.
— Transaction : Le module Transaction prend en charge la gestion de transaction program-
matique et déclarative pour les classes implémentant des interfaces spéciales et pour tous
vos POJO.
Le module AOP fournit une implémentation de programmation orientée aspect qui permet de
définir des intercepteurs de méthode et des découpes en points afin de découpler proprement le
code implémentant des fonctionnalités à séparer.
Spring Aspects
Le module Aspects fournit une intégration à AspectJ, qui est à nouveau un cadre AOP puissant
et mature.
Spring Instrumentation
Spring Messaging
Le module de messagerie prend en charge STOMP en tant que sous-protocole WebSocket à utiliser
dans les applications. Il prend également en charge un modèle de programmation d’annotation
pour le routage et le traitement des messages STOMP provenant de clients WebSocket.
Implémentation du modèle MVC. Personnellement j’utilise plutôt Struts mais c’est surtout une
question d’habitude, c’est là la grande force de Spring, rien ne vous oblige à tout utiliser et vous
pouvez tout mélanger. Ce qui n’est pas forcément une bonne idée mais nous en reparlerons.
La couche Web comprend les modules Web, Web-MVC, Web-Socket et Web-Portlet, dont les
détails sont les suivants :
— Web : Le module Web fournit des fonctionnalités d’intégration Web de base, telles que
la fonctionnalité de téléchargement de fichiers en plusieurs parties et l’initialisation du
conteneur IoC à l’aide d’écouteurs de servlets et d’un contexte d’application Web.
— Web-MVC : Le module Web-MVC contient l’implémentation MVC (Model-View-Controller)
de Spring pour les applications Web.
Spring Test
Le module Test prend en charge le test des composants Spring avec les frameworks JUnit ou
TestNG.
void show(){
[Link]
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="[Link]
xmlns:xsi="[Link]
xmlns:p="[Link]
xsi:schemaLocation="[Link]
[Link]
</beans>
[Link]
package [Link];
import [Link];
import [Link];
import [Link].*;
Employee s=(Employee)[Link]("e");
[Link]();
}
}
S’il existe une relation HAS-A entre les classes, nous créons d’abord l’instance de l’objet dépen-
dant (objet contenu) puis la transmettons comme argument du constructeur de classe principal.
Ici, notre scénario est l’adresse de l’employé HAS-A. L’objet de classe Adresse sera appelé objet
dépendant.
[Link]
package [Link];
void show(){
[Link](id+" "+name);
[Link]([Link]());
}
[Link]
<?xml version="1.0" encoding="UTF-8"?>
</beans>
[Link]
package [Link];
import [Link];
import [Link];
import [Link].*;
Employee s=(Employee)[Link]("e");
[Link]();
}
}
Le framework Spring présente de nombreux avantages par rapport aux frameworks ORM. Il y a
comme suit :
— Moins de codage est requis : grâce au framework Spring, vous n’avez pas besoin d’écrire de
codes supplémentaires avant et après la logique de base de données réelle, comme obtenir
la connexion, démarrer la transaction, valider la transaction, fermer la connexion, etc.
— Facile à tester : l’approche IoC de Spring facilite le test de l’application.
— Meilleure gestion des exceptions : le framework Spring fournit sa propre API pour la
gestion des exceptions avec le framework ORM.
— Gestion intégrée des transactions : à l’aide du framework Spring, nous pouvons envelopper
notre code de mappage avec une classe wrapper de modèle explicite ou un intercepteur de
méthode de style AOP.
Un Spring MVC fournit une solution élégante pour utiliser MVC dans le framework Spring à
l’aide de DispatcherServlet. Ici, DispatcherServlet est une classe qui reçoit la demande entrante
et la mappe à la bonne ressource telle que les contrôleurs, les modèles et les vues
— Comme le montre la figure, toutes les requêtes entrantes sont interceptées par le Dispat-
cherServlet qui fait office de contrôleur frontal.
— Le DispatcherServlet obtient une entrée de mappage de gestionnaire à partir du fichier
XML et transmet la demande au contrôleur.
— Le contrôleur renvoie un objet de ModelAndView.
— Le DispatcherServlet vérifie l’entrée du résolveur de vue dans le fichier XML et appelle le
composant de vue spécifié.
C’est un sous-projet du framework Spring qui a été lancé en 2003 par Ben Alex. Plus tard, en
2004, il a été publié sous la licence Apache sous le nom de Spring Security 2.0.0.
Il surmonte tous les problèmes qui surviennent lors de la création d’applications de sécurité non
Spring et gère un nouvel environnement de serveur pour l’application.
Ce cadre cible deux domaines d’application majeurs sont l’authentification et l’autorisation. L’au-
thentification est le processus de connaissance et d’identification de l’utilisateur qui souhaite ac-
céder.
L’autorisation est le processus permettant à l’autorité d’effectuer des actions dans l’application.
Nous pouvons appliquer une autorisation pour autoriser la demande Web, les méthodes et l’accès
à un domaine individuel.
La beauté de ce cadre est sa nature d’authentification flexible pour s’intégrer à n’importe quelle
solution logicielle. Parfois, les développeurs souhaitent l’intégrer à un système hérité qui ne res-
pecte aucune norme de sécurité, Spring Security fonctionne bien.
[Link]
<beans:beans xmlns="[Link]
xmlns:beans="[Link]
xmlns:xsi="[Link]
xsi:schemaLocation="[Link]
[Link]
[Link]
[Link]
<http auto-config="true">
<intercept-url pattern="/admin" access="hasRole('ROLE_ADMIN')" />
</http>
<authentication-manager>
<authentication-provider>
<user-service>
<user name="admin" password="1234" authorities="hasRole(ROLE_ADMIN)" />
</user-service>
</authentication-provider>
</authentication-manager>
</beans:beans>
[Link]
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
Il s’agit d’un module Spring qui fournit la fonctionnalité RAD (Rapid Application Development)
au framework Spring. Il est utilisé pour créer une application autonome basée sur Spring qu’on
peut simplement exécuter car elle nécessite une configuration Spring minimale.
Dans Spring Boot, la configuration XML (descripteur de déploiement) n’est pas requise. Il utilise
la convention sur le paradigme de conception de logiciel de configuration, ce qui signifie qu’il
diminue l’effort du développeur.
On peut utiliser Spring STS IDE ou Spring Initializr pour développer des applications Java
Spring Boot.
— Il crée des applications Spring autonomes qui peuvent être démarrées à l’aide de Java -jar.
— Il teste facilement les applications Web à l’aide de différents serveurs HTTP embarqués
tels que Tomcat, Jetty, etc.
— Il fournit des POM « de démarrage » avisés pour simplifier notre configuration Maven.
— Il fournit des fonctionnalités prêtes pour la production telles que des métriques, des véri-
fications de l’état et une configuration externalisée.
— Il n’y a aucune exigence pour la configuration XML.
— Il offre un outil CLI pour développer et tester l’application Spring Boot.
— Il offre le nombre de plug-ins.
— Il minimise également l’écriture de plusieurs codes passe-partout (le code qui doit être
inclus à de nombreux endroits avec peu ou pas de modification), la configuration XML et
les annotations.
— Il augmente la productivité et réduit le temps de développement.
Avant de comprendre l’architecture Spring Boot, nous devons connaître les différentes couches et
classes qui y sont présentes. Il y a quatre couches dans Spring Boot :
— Couche de présentation
— Couche métier
— Couche de persistance
— Couche de base de données
Business Layer : La couche métier gère toute la logique métier. Il se compose de classes de ser-
vices et utilise des services fournis par des couches d’accès aux données. Il effectue également
l’autorisation et la validation.
Persistence Layer : la couche de persistance contient toute la logique de stockage et traduit les
objets métier depuis et vers les lignes de la base de données.
Database Layer : dans la couche de base de données, les opérations CRUD (create, retrive, update,
delete) sont effectuées.
Spring Boot Annotations est une forme de métadonnées qui fournit des données sur un pro-
gramme. En d’autres termes, les annotations sont utilisées pour fournir des informations supplé-
mentaires sur un programme. Il ne fait pas partie de l’application que nous développons. Cela
n’a pas d’effet direct sur le fonctionnement du code qu’ils annotent. Cela ne change pas l’action
du programme compilé.
— @Required : Cela s’applique à la méthode du bean setter. Il indique que le bean annoté
doit être rempli au moment de la configuration avec la propriété requise, sinon il lève une
exception BeanInitilizationException.
— @Autowired : Spring fournit un câblage automatique basé sur des annotations en four-
nissant une annotation @Autowired. Il est utilisé pour câbler automatiquement le bean
à ressort sur les méthodes setter, la variable d’instance et le constructeur. Lorsque nous
utilisons l’annotation @Autowired, le conteneur Spring câble automatiquement le bean en
faisant correspondre le type de données.
— @ComponentScan : il est utilisé lorsque nous voulons analyser un paquet pour les beans.
Il est utilisé avec l’annotation @Configuration. Nous pouvons également spécifier les pa-
ckages de base à analyser pour les composants Spring.
— @Bean : C’est une annotation au niveau de la méthode. C’est une alternative à la balise
XML <bean>. Il indique à la méthode de produire un bean à gérer par Spring Container.
— @Component : il s’agit d’une annotation au niveau de la classe. Il est utilisé pour marquer
une classe Java en tant que bean. Une classe Java annotée avec @Component est trouvée
pendant le chemin de classe. Le Spring Framework le récupère et le configure dans le
contexte de l’application en tant que Spring Bean.
— @Controller : Le @Controller est une annotation au niveau de la classe. C’est une spéciali-
sation de @Component. Il marque une classe en tant que gestionnaire de requêtes Web. Il
est souvent utilisé pour servir des pages Web. Par défaut, il renvoie une chaîne qui indique
la route à rediriger. Il est principalement utilisé avec l’annotation @RequestMapping.
— @Service : Il est également utilisé au niveau de la classe. Il indique au Spring que la classe
contient la logique métier.
— @RequestMapping : Il est utilisé pour mapper les requêtes Web. Il contient de nombreux
éléments facultatifs tels que consomme, en-tête, méthode, nom, paramètres, chemin, pro-
duit et valeur. Nous l’utilisons avec la classe ainsi que la méthode.
— @GetMapping : il mappe les requêtes HTTP GET sur la méthode de gestionnaire spéci-
fique. Il est utilisé pour créer un point de terminaison de service Web qui récupère Il est
utilisé au lieu d’utiliser : @RequestMapping(method = [Link])
— @PutMapping : il mappe les requêtes HTTP PUT sur la méthode de gestionnaire spéci-
fique. Il est utilisé pour créer un point de terminaison de service Web qui crée ou met à
jour Il est utilisé au lieu d’utiliser : @RequestMapping(method = [Link])
— @RequestBody : Il est utilisé pour lier une requête HTTP à un objet dans un paramètre
de méthode. En interne, il utilise des convertisseurs de messages HTTP pour convertir le
corps de la requête. Lorsque nous annotons un paramètre de méthode avec @RequestBody,
le framework Spring lie le corps de la requête HTTP entrante à ce paramètre.
— @ResponseBody : il lie la valeur de retour de la méthode au corps de la réponse. Il in-
dique au Spring Boot Framework de sérialiser un objet de retour au format JSON et XML.
— @PathVariable : Il est utilisé pour extraire les valeurs de l’URI. Il convient le mieux au
service Web RESTful, où l’URL contient une variable de chemin. Nous pouvons définir
plusieurs @PathVariable dans une méthode.
— @RequestParam : Il est utilisé pour extraire les paramètres de la requête de l’URL. Il est
également appelé paramètre de requête. Il est le plus approprié pour les applications Web.
Il peut spécifier des valeurs par défaut si le paramètre de requête n’est pas présent dans
l’URL.
— @RequestHeader : Il est utilisé pour obtenir les détails sur les en-têtes de requête HTTP.
Nous utilisons cette annotation comme paramètre de méthode. Les éléments facultatifs
de l’annotation sont name, required, value, defaultValue. Pour chaque détail de l’en-tête,
nous devons spécifier des annotations distinctes. Nous pouvons l’utiliser plusieurs fois dans
une méthode.
Spring Boot Framework est livré avec un mécanisme intégré pour la configuration de l’application
à l’aide d’un fichier appelé [Link]. Il est situé dans le dossier src/main/resources.
Spring Boot fournit diverses propriétés qui peuvent être configurées dans le fichier applica-
[Link]. Les propriétés ont des valeurs par défaut. Nous pouvons définir une ou plusieurs
propriétés pour l’application Spring Boot. Spring Boot nous permet également de définir notre
propre propriété si nécessaire.
— C’est un moteur de template écrit en Java traitant les fichiers XML, XHTML et HTML5.
— Thymeleaf permet de traiter à la fois les fichiers appartenant à un site web ou non. Il n’y
a pas dépendance vis-à-vis de l’API Servlet.
— Thymeleaf est composé de plusieurs modules appelés dialecte :
— Les caractéristiques d’un dialecte s’appliquent à travers les balises et/ou les attributs des
templates.
— Deux dialectes sont disponibles : Standard et le SpringStandard (pour les applications
Spring MVC mais en utilisant la même syntaxe que le dialecte Standard).
— Les développeurs peuvent étendre les fonctionnalités des dialectes proposés ou bien créer
leur propre dialecte.
— Plusieurs modes de template sont disponibles :
XML
XHTML 1.0 and 1.1
HTML5
— Le support de l’internationalisation des textes.
— La mise en œuvre d’un cache performant et configurable permet de réduire les entrées/-
sorties.
— Thymeleaf est extrêmement extensible et peut être utilisé comme framework de template.
— Une documentation très complète contenant de nombreux exemples est disponible.
Exemple
<table>
48
REST
REST (Representational State Transfer) est une architecture de services Web. Élaborée en l’an
2000 par Roy Fiedling, l’un des créateurs du protocole HTTP, du serveur Apache HTTPd et
d’autres travaux fondamentaux, REST est une manière de construire une application pour les
systèmes distribués comme le World Wide Web.
XML-RPC
XML-RPC est un protocole simple utilisant XML pour effectuer des messages RPC. Les requêtes
sont écrites en XML et envoyées via HTTP POST. Les requêtes sont intégrées dans le corps de la
réponse HTTP. XML-RPC est indépendant de la plate-forme, ce qui lui permet de communiquer
avec diverses applications. Par exemple, un client Java peut parler de XML-RPC à un PerlServer !
SOAP
SOAP (Simple object Access Protocol) est un protocole standard de communication. C’est l’épine
dorsale du système d’interopérabilité. SOAP est un protocole décrit en XML et standardisé par le
W3C. Il se présente comme une enveloppe pouvant être signée et pouvant contenir des données ou
des pièces jointes. Il circule sur le protocole HTTP et permet d’effectuer des appels de méthodes
à distance.
WSDL
WSDL (Web Services Description Language) est un langage de description standard. C’est l’in-
terface présentée aux utilisateurs. Il indique comment utiliser le service Web et comment interagir
avec lui. WSDL est basé sur XML et permet de décrire de façon précise les détails concernant le
service Web tels que les protocoles, les ports utilisés, les opérations pouvant être effectuées, les
formats des messages d’entrée et de sortie et les exceptions pouvant être envoyées.
UDDI
UDDI (Universal Description, Discovery and Integration) est un annuaire de services. Il fournit
l’infrastructure de base pour la publication et la découverte des services Web. UDDI permet aux
fournisseurs de présenter leurs services Web aux clients.
Hors ici on ne s’appuie pas sur le verbe HTTP GET pour indiquer le type d’action que l’on désire
appliquer, dans un cadre RESTFul on devrait faire :
DELETE /<context-root>/livre/1
5.2.2 JAX-RS
Par la suite nous parlerons de JAX-RS 2.0 qui est fournit par JEE7 qui correspond à la JSR 339
qui succède à JAX-RS 1 qui découle de la JSR 311.
Service REST
[Link]
package [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
@Path("/ma-ressource")
public class MaRessourceRest {
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getMesRessources() {
// retourne une liste de ressoure List et un code HTTP 200
return [Link]([Link]()).build();
}
@GET
@Path("/{id}")
@Produces(MediaType.APPLICATION_JSON)
public Response getMaRessourceParId( @PathParam("id") String id) {
// retourne une ressoure : MaRessource et un code HTTP 200
return [Link](([Link](id)).build
();
}
@POST
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public Response createMaRessource( MaRessourceJson maRessource ) {
// crée une ressoure MaRessource
//retourne l'ID de la ressource et un code HTTP 201
MaRessourceJson result = [Link](maRessource);
return [Link]([Link]).entity([Link]()).build();
}
@PUT
@Path("/{id}")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public Response updateMaRessource( @PathParam("id") String id, MaRessourceJson
maRessource) {
// retourne la ressource et un code HTTP 200
[Link](maRessource);
return [Link](maRessource).build();
}
[Link]
package [Link];
import [Link];
[Link]
<servlet>
<servlet-name>JerseyDemo</servlet-name>
<servlet-class>[Link]</servlet-class
>
<!-- Define the ResourceConfig class -->
<init-param>
<param-name>[Link]</param-name>
<param-value>[Link]</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
[Link]
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
public class ClientRest {
public static void main(String[] args){
Client client =
[Link]().newClient();
WebTarget target =
[Link]("[Link]
target = [Link]("ma-ressource/" + 1);
[Link] builder = [Link]();
Response response = [Link]();
MaRessource maRessource =
[Link]([Link]);
} }
[Link]
<dependencies>
<dependency>
<groupId>[Link]</groupId>
<!-- if your container implements Servlet API older than 3.0, use "jersey-
container-servlet-core" -->
<artifactId>jersey-container-servlet</artifactId>
<version>2.32</version>
</dependency>
<!-- Required only when you are using JAX-RS Client -->
<dependency>
<groupId>[Link]</groupId>
<artifactId>jersey-client</artifactId>
<version>2.32</version>
</dependency>
<dependency>
<groupId>[Link]</groupId>
<artifactId>jersey-hk2</artifactId>
<version>2.32</version>
</dependency>
</dependencies>
5.3.1 Introduction
Les services Web RESTful sont des applications client et serveur qui communiquent sur le Web.
Les services Web RESTful sont des services Web basés sur l’architecture REST. Dans l’architec-
ture REST, tout est ressource. Les services Web RESTful assurent la communication entre les
applications logicielles s’exécutant sur différentes plates-formes et frameworks. On peut considé-
rer les services web comme du code à la demande. Un service Web RESTful est une fonction
ou une méthode qui peut être appelée en envoyant une requête HTTP à une URL, et le service
renvoie le résultat comme réponse. Dans ce didacticiel, vous apprendrez les bases des services
Web RSETful avec des exemples et des projets appropriés.
La ressource a des représentations telles que XML, HTML et JSON. Capture de l’état actuel par
ressource de représentation. Lorsque nous demandons une ressource, nous fournissons la repré-
sentation de la ressource. Les méthodes importantes de HTTP sont :
Par exemple, si nous voulons effectuer les actions suivantes dans l’application de médias sociaux,
nous obtenons les résultats correspondants.
[Link]
package [Link];
public class HelloWorldBean
{
public String message;
//constructor of HelloWorldBean
public HelloWorldBean(String message)
{
[Link]=message;
}
//generating getters and setters
public String getMessage()
{
return message;
}
public void setMessage(String message)
{
[Link] = message;
}
@Override
On peut aussi améliorer le service Hello World avec une variable de chemin.
[Link]
package [Link];
import [Link];
import [Link];
import [Link];
import [Link];
@Configuration
//Controller
@RestController
public class HelloWorldController
{
//using get method and hello-world URI
@GetMapping(path="/hello-world")
public String helloWorld()
{
return "Hello World";
}
@GetMapping(path="/hello-world-bean")
//method- which returns "Hello World"
public HelloWorldBean helloWorldBean()
{
return new HelloWorldBean("Hello World");//constructor of HelloWorldBean
}
//passing a path variable
@GetMapping(path="/hello-world/path-variable/{name}")
public HelloWorldBean helloWorldPathVariable(\@PathVariable String name)
{
return new HelloWorldBean([Link]("Hello World,%s", name)); //%s replace the
name
}
}
Selon James Lewis et Martin Fowler, « le style architectural de microservice est une approche
pour développer une application unique en tant que suite de petits services. Chaque microservice
exécute son processus et communique avec des mécanismes légers. Ces services sont construits
autour de capacités commerciales et développés indépendamment par machines de déploiement
entièrement automatisées."
Il existe un strict minimum de gestion centralisée de ces services, qui peuvent être écrits dans
différents langages de programmation et utiliser différentes technologies de stockage de données.
Le microservice définit une approche de l’architecture qui divise une application en un pool de
services faiblement couplés qui implémentent les exigences métier. C’est à côté de l’architecture
orientée services (SOA). La caractéristique la plus importante de l’architecture basée sur des
microservices est qu’elle peut effectuer la livraison continue d’une application volumineuse et
complexe.
Le microservice aide à casser l’application et à créer des applications plus petites logiquement
indépendantes. Par exemple, nous pouvons créer une application cloud avec l’aide d’Amazon
AWS avec un minimum d’efforts.
58
Les principes des Microservices :
— Principe de responsabilité unique
— Modélisé autour du domaine d’activité
— Isoler l’échec
— Automatisation des infrastructures
— Déployer indépendamment
L’architecture des microservices est plus complexe que l’ancien système. L’environnement de
microservice devient plus compliqué car l’équipe doit gérer et prendre en charge de nombreuses
pièces mobiles.
En d’autres termes, le service est propriétaire de ses données et est responsable de leur intégrité
et de leur mutabilité. Il prend en charge la caractéristique la plus importante des microservices,
à savoir l’indépendance et le découplage.
6.2.3 Surveillance
La méthode traditionnelle de surveillance ne s’alignera pas bien avec les microservices, car nous
avons plusieurs services constituant la même fonctionnalité précédemment pris en charge par une
Ces principes nous permettent d’aborder les évolutions technologiques associées aux microservices
et les changements organisationnels qui leur sont liés.
Spring Cloud Config Server fournit l’API basée sur les ressources HTTP pour la configuration
externe dans le système distribué. Nous pouvons activer Spring Cloud Config Server en utilisant
l’annotation @EnableConfigServer.
— L’équilibrage de charge
— Tolérance aux pannes
— Plusieurs protocoles (HTTP, TCP, UDP)
— Mise en cache et traitement par lots
6.6.1 Aggregator
Agrégateur dans le monde informatique fait référence à un site Web ou à un programme qui
collecte des éléments de données connexes et les affiche. Ainsi, même dans les modèles de mi-
croservices, Aggregator est une page Web de base qui appelle divers services pour obtenir les
Ainsi, par exemple, si vous envisagez deux services : les services A et B, on pwut mettre à
l’échelle individuellement ces services simultanément en fournissant les données au microservice
composite.
Eh bien, la solution à ce genre de problèmes pourrait être l’API Gateway Design Pattern. L’API
Gateway Design Pattern répond non seulement aux problèmes mentionnés ci-dessus, mais il résout
de nombreux autres problèmes. Ce modèle de conception de microservice peut également être
considéré comme le service proxy pour router une requête vers le microservice concerné. Étant
une variante du service Agrégateur, il peut envoyer la demande à plusieurs services et agréger
de la même manière les résultats au composite ou au service consommateur. API Gateway agit
également comme point d’entrée pour tous les microservices et crée des API à grain fin pour
différents types de clients.
Un autre aspect important que vous devez comprendre est que la demande du service A au service
B peut être différente du service B au service C. De même, la réponse du service C au service B
peut être complètement différente du service B au service A.
6.6.7 Branch
Le modèle de conception de microservice de branche est un modèle de conception dans lequel
vous pouvez traiter simultanément les demandes et les réponses de deux ou plusieurs microser-
vices indépendants. Ainsi, contrairement au modèle de conception chaîné, la demande n’est pas
transmise dans une séquence, mais la demande est transmise à deux ou plusieurs chaînes de
microservices mutuellement exclusives. Ce modèle de conception étend le modèle de conception
Agrégateur et offre la possibilité de produire des réponses à partir de plusieurs chaînes ou d’une
seule chaîne. Par exemple, si vous envisagez une application de commerce électronique, vous de-
vrez peut-être récupérer des données à partir de plusieurs sources et ces données pourraient être
une sortie collaborative de données de divers services. Ainsi, vous pouvez utiliser le modèle de
branche pour récupérer des données à partir de plusieurs sources.
Ainsi, pour éviter de tels problèmes, vous pouvez utiliser le modèle de conception de disjoncteur.
À l’aide de ce modèle, le client invoquera un service distant via un proxy. Ce proxy se comportera
essentiellement comme une barrière de circuit. Ainsi, lorsque le nombre de défaillances dépasse
le nombre seuil, le disjoncteur se déclenche pendant une période de temps particulière. Ensuite,
toutes les tentatives d’appel du service distant échoueront pendant cette période d’expiration.
Une fois cette période écoulée, le disjoncteur laissera passer un nombre limité de tests et si ces
demandes aboutissent, le disjoncteur reprend son fonctionnement normal. Sinon, s’il y a un échec,
le délai d’attente recommence.
À l’aide de ce modèle, vous pouvez décomposer une application en fonction des capacités com-
merciales ou en fonction des sous-domaines.
[Link]
[Link]=8761
[Link]-with-eureka=false
importer [Link] ;
@EnableEurekaServer
@SpringBootApplication
Après son démarrage, vous devriez pouvoir ouvrir http ://localhost :8761 et voir qu’aucun service
n’est disponible. Ouvrez maintenant http ://localhost :8761. Ici, Spring Eureka Server s’ouvrira
et affichera qu’aucun service ne sera en cours d’exécution.
— Actuator : des fonctionnalités pour vous aider à surveiller et gérer votre application
— Eureka Discovery : pour l’inscription au service
— JPA : pour sauvegarder/récupérer des données
— Mysql : une base de données en mémoire
— Rest Repositories : pour exposer les référentiels JPA en tant que points de terminaison
REST
— Web : Spring MVC et Tomcat embarqué
— DevTools : pour recharger automatiquement l’application lorsque les fichiers changent
— Lombok : pour réduire le code passe-partout
[Link]
[Link]=8088\newline
[Link]=item-catalog-service\newline
Maintenant, pour démarrer l’application : Ouvrir maintenant http ://localhost :8761. Ici, vous
verrez que le service de catalogue d’articles sera en cours d’exécution.
Étant donné que le service item-catalog-service s’exécute sur le port 8088, vous devrez configurer
cette application pour qu’elle s’exécute sur un port différent. Modifiez edge-service/src/main/resources/appl
pour définir le port sur 8089 et définissez un nom d’application.
[Link]
[Link]=8089
[Link]=edge-service
[Link]
[Link]=${[Link][0]:localhost}
[Link]=80
[Link]=${[Link].instance_id:${spring.
[Link]}:${[Link].instance_id:${[Link]}}}
[Link] = 5
[Link] = default
[Link] = 5
[Link]=${[Link]
.uri}/eureka/
Pour activer Feign, Hystrix et l’enregistrement auprès du serveur Eureka, ajoutez les annotations
appropriées à [Link] :
[Link]
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
@EnableFeignClients
@EnableCircuitBreaker
@EnableDiscoveryClient
@EnableZuulProxy
@SpringBootApplication
public class EdgeServiceApplication {
Créer un Item DTO (Data Transfer Object) dans ce même fichier. @Data de Lombok générera
des méthodes toString(), des getters, des setters et des constructeurs appropriés.
Créer une interface ItemClient qui utilise Feign pour communiquer avec le service Item-catalog-
service.
[Link]
public class EdgeServiceApplication {
@Data
class Item {
private String name;
}
@GetMapping("/items")
Resources<Item> readItems();
}
Créer un RestController sous l’ItemClient qui filtrera les marques inférieures aux meilleures et
affichera un /top-brandsendpoint.
[Link]
@RestController
class GoodItemApiAdapterRestController {
@HystrixCommand(fallbackMethod = "fallback")
@GetMapping("/top-brands")
public Collection<Item> goodItems() {
return [Link]()
.getContent()
.stream()
.filter(this::isGreat)
.collect([Link]());
}
Démarrez l’application de service de périphérie avec Maven ou votre IDE et vérifiez qu’elle
s’enregistre avec succès auprès du serveur Eureka.
Si on ferme l’application item-catalog-service, vous obtiendrez une erreur de serveur interne 500.
Pour résoudre ce problème, on peut utiliser Hystrix pour créer une méthode de secours et indiquer
à la méthode goodItems() de l’utiliser.
@HystrixCommand(fallbackMethod = "fallback")
78