Concepts Java : Encapsulation, Héritage, Polymorphisme, Abstraction
Concepts Java : Encapsulation, Héritage, Polymorphisme, Abstraction
I- Concepts du POO
1- L'encapsulation : est le mécanisme qui permet de cacher les détails d'implémentation
d'un objet, en limitant l'accès aux attributs et aux méthodes de l'objet.
Cela peut être réalisé en déclarant une variable importante comme privée et en
fournissant des méthodes getter et setter publiques.
Les modificateurs d'accès : Ils s'appliquent aux classes, aux méthodes et aux attributs.
➔ public, default: package-private, protected and private.
Public : Une variable, méthode ou classe déclarée public est visible par tous les autres
objets.
Default : C’est le niveau par défaut lorsqu'aucun modificateur n'est précisé. Cette
déclaration permet à une entité (classe, méthode ou variable) d'être visible par toutes les
classes se trouvant dans le même package.
Protected : Si une méthode ou une variable est déclarée protected, seules les méthodes
présentes dans le même package que cette classe ou ses sous-classes pourront y accéder.
On ne peut pas qualifier une classe avec protected.
• Le but principal du mot-clé protected est de faire hériter la méthode ou la variable au classes
filles.
Private : C'est le niveau de protection le plus fort. Les composants ne sont visibles qu'à
l'intérieur de la classe. Les méthodes déclarées private ne peuvent pas être en même temps
déclarées abstract car elles ne peuvent pas être redéfinies dans les classes filles.
Elle permet de protéger l'état interne de l'objet contre les modifications non autorisées
ou les erreurs de programmation.
Le regroupement de données et d'opérations à effectuer sur ces données en une seule
unité est appelé encapsulation.
2- Héritage :
Comme son nom l'indique, est utilisé pour hériter des propriétés de la classe parent à la
classe enfant
C’est un mécanisme qui facilite la réutilisation du code et la gestion de son évolution.
Abstract indique que la classe ne pourra être instanciée telle quelle. De plus, toutes les méthodes de
cette classe abstract qui ne sont pas implémentées, devront être redéfinies par des méthodes complètes
dans ses sous-classes.
this : Cette variable sert à référencer dans une méthode l'instance de l'objet en cours d'utilisation. this
est un objet qui est égal à l'instance de l'objet dans lequel il est utilisé.
Static : Est utilisé pour définir des éléments qui appartiennent à la classe elle-même plutôt qu'à une
instance particulière de la classe.
- Les variables d'instance sont des variables propres à un objet. Il est possible de définir une
variable de classe qui est partagée entre toutes les instances d'une même classe : elle
n'existe donc qu'une seule fois en mémoire.
Une telle variable permet de stocker une constante ou une valeur modifiée par les
instances de la classe.
- Une méthode static est une méthode qui n'agit pas sur des variables d'instance mais
uniquement sur des variables de classe. Ces méthodes peuvent être utilisées sans instancier
un objet de la classe. Les méthodes ainsi définies peuvent être appelées avec la notation
[Link]() au lieu de [Link]() : la première forme est fortement recommandée
pour éviter toute confusion.
Il n'est pas possible d'appeler une méthode d'instance ou d'accéder à une variable
d'instance à partir d'une méthode de classe statique.
Final : est utilisé pour définir une constante, une variable ou une méthode qui ne peut pas être modifiée
ou redéfinie par la suite.
Définition de constantes : en utilisant final avec static, on peut définir une variable constante de classe
qui ne peut pas être modifiée.
Protection contre la redéfinition : en utilisant final avec une méthode, on peut empêcher les sous-classes
de la redéfinir.
Lorsqu'une classe est marquée comme final, cela signifie qu'on ne peut pas l’étendre.
III- Nouveautés java 8 :
1- Les expressions lambda
Une expression lambda est une fonction anonyme : sa définition se fait sans déclaration explicite
du type de retour, ni de modificateurs d'accès ni de nom. C'est un raccourci syntaxique qui permet
de définir une méthode directement à l'endroit où elle est utilisée.
Une expression lambda simplifie l'écriture de traitements passés en paramètre. Elle est
particulièrement utile notamment lorsque le traitement n'est utile qu'une seule fois : elle évite
d'avoir à écrire une méthode dans une classe.
C'est un raccourci syntaxique aux classes anonymes internes pour une interface qui ne possède
qu'une seule méthode abstraite. Ce type d'interface est nommée interface fonctionnelle.
Serveur d’application VS Serveur Web
Serveur Web :
Fonction : Le serveur web est principalement responsable de traiter les requêtes HTTP (Hypertext
Transfer Protocol) envoyées par les clients (navigateurs web) et de renvoyer les réponses appropriées,
généralement des pages web, des images, des fichiers, etc.
Services : Il s'agit généralement d'un serveur statique qui répond à des requêtes pour des ressources
statiques telles que les fichiers HTML, CSS, JavaScript, images, etc.
Langages de programmation : Les serveurs web peuvent être configurés pour gérer des langages de
programmation côté serveur tels que PHP, Python, ou Ruby, mais leur principale fonction reste de
répondre aux requêtes HTTP avec des ressources statiques.
Exemple : Apache.
Serveur d'Application :
Fonction : Le serveur d'application est conçu pour gérer des applications web plus complexes et
dynamiques. Il traite les demandes des clients en exécutant du code applicatif, accédant à des bases de
données et générant des pages web dynamiquement.
Services : Il prend en charge l'exécution d'applications d'entreprise et traite généralement des opérations
commerciales complexes, telles que la gestion des transactions, l'authentification des utilisateurs, la
sécurité, etc.
Exemple : Tomcat.
SOAP VS REST
REST (Representational State Transfer) : style architecture logicielle basé sur des principes et des
contraintes architecturales qui définissent comment les services web doivent être conçus et exposés.
Dans l'architecture REST, les ressources sont identifiées par des URLs (Uniform Resource Locators) et
sont manipulées à l'aide des méthodes HTTP telles que GET, POST, PUT et DELETE. Les données sont
généralement échangées au format JSON (JavaScript Object Notation) ou XML (eXtensible Markup
Language).
En revanche, SOAP (Simple Object Access Protocol) est un protocole de communication spécifique qui
utilise des messages XML pour l'échange de données entre les services web. SOAP nécessite une
structure XML plus complexe, comprenant une enveloppe SOAP, un en-tête et un corps de message.
L’envoi d’une requête de donnée à une API REST se fait par le protocole HTTP. A la réception de la
requête, les API REST peuvent envoyer des messages dans différents formats : HTML, JSON, TEXT…
➔JSON est le plus utilisé car il est plus léger et lisible par tous les langages de programmation.
Les principes et contraintes architecturales qui définissent la conception et l'exposition des services web
selon le style architectural REST sont les suivants :
Spring est un portfolio de nombreux projets qui couvrent un grand nombre de besoins. Tous ces projets
reposent sur le cœur de Spring : Spring Core.
Spring simplifie également la configuration des applications Java en utilisant l'injection de dépendances et
l'inversion de contrôle.
Spring Core (également appelé Spring Framework) est un framework de développement d'applications
Java open-source. Il fournit une infrastructure complète pour le développement d'applications Java, en
offrant des fonctionnalités telles que l'injection de dépendances, la gestion de la configuration, la
création de beans, la gestion des transactions, la sécurité, la gestion des événements et bien plus encore.
L'inversion de contrôle (IoC) est un principe de conception dans lequel le contrôle du flux d'exécution
d'une application est inversé, c'est-à-dire que la responsabilité de la gestion des dépendances et de
l'exécution du code est transférée à un conteneur ou un framework.
L'IoC est un principe abstrait qui définit un motif de conception dans lequel le flux de contrôle d'un
système est inversé par rapport à un développement procédural.
IoC permet à un framework de contrôler le flux d'un programme et d'appeler notre code personnalisé.
En d'autres termes, l'objet n'a plus le contrôle de la création ou de la gestion de ses dépendances, mais il
les reçoit plutôt d'un conteneur ou d'un framework qui a été configuré pour fournir ces dépendances.
L'injection de dépendances (DI) est un principe de conception qui favorise la séparation des
préoccupations et la modularité en fournissant les dépendances nécessaires à un objet plutôt que de les
créer directement. Cela permet de rendre les objets plus flexibles, réutilisables et faciles à tester.
L'injection de dépendances est un motif de conception qui propose un mécanisme pour fournir à un
composant les dépendances dont il a besoin. C'est une forme particulière d'inversion de contrôle.
Dans le cas classique, l'objet invoque le constructeur de ses dépendances pour obtenir les instances
requises en utilisant l'opérateur new.
Les dépendances d'un objet ne sont pas gérées par l'objet lui-même mais sont gérées et injectées par une
entité externe à l'objet.
L’injection de dépendance est une fonctionnalité clé du Spring Core (le cœur de Spring).
Spring propose d'autres portées notamment celles dédiées aux applications web (request, session et
global-session).
Spring Boot est une extension du framework Spring qui facilite la création d'applications Java. Il fournit
une configuration automatique pour de nombreux modules Spring courants, ce qui réduit
considérablement le temps et la complexité de la configuration manuelle d'une application.
Spring boot facilite le développement et la création des applications basées sur Spring et Java avec un
minimum de configuration.
Par exemple il nous fournit le fichier [Link] où on déclare les propriétés nécessaires pour
l'application, de cette façon il élimine les tâches pénibles de configuration.
En plus il nous offre une liste des annotations qui simplifient plusieurs tâches tel que le scan.
Un starter est un ensemble de descripteurs de dépendances pratiques que l'on peut utiliser dans notre
application.
Spring Boot nous offre aussi le principe d'auto configuration, c à dire il nous permet de créer nos custom
beans.
Dans Spring Boot il n’ya aucune exigence de configurations XML (descripteurs de déploiement).
Il utilise le paradigme de conception logiciel « Convention Over Configuration » ce qui diminue l’effort du
développeur.
Il existe plusieurs projets frères de Spring, qui fournissent des fonctionnalités supplémentaires et
complémentaires pour le développement d'applications Java. Voici quelques-uns des projets frères de
Spring les plus importants :
1- Spring Data : fournit une abstraction pour l'accès aux bases de données et facilite le
développement d'applications d'accès aux données.
2- Spring Security : fournit une infrastructure de sécurité pour les applications Java, avec des
fonctionnalités telles que l'authentification, l'autorisation et la protection contre les attaques.
3- Spring Batch : fournit un framework pour le traitement de données en batch, avec des
fonctionnalités telles que le traitement parallèle, la reprise après erreur et les notifications
d'état.
4- Spring Integration : fournit une infrastructure pour l'intégration de systèmes, avec des
fonctionnalités telles que la transformation de données, la gestion des erreurs et la
communication asynchrone.
5- Spring Cloud : fournit des outils pour le développement d'applications cloud-native, avec des
fonctionnalités telles que la découverte de services, la configuration distribuée et la gestion de
la tolérance aux pannes.
Spring starters :
Les Spring Starters sont des modules Spring Boot qui contiennent un ensemble prédéfini de
dépendances courantes pour des fonctionnalités spécifiques, afin de faciliter et d'accélérer le processus
de configuration des applications.
Les starters de Spring Boot sont généralement nommés en fonction de la fonctionnalité qu'ils fournissent,
par exemple :
1- Tout d'abord, Spring Boot scanne le classpath à la recherche des composants de l'application.
Cela inclut les contrôleurs, les services, les repositories, etc. Ces composants sont détectés
automatiquement grâce à l'annotation @ComponentScan, qui se trouve généralement dans la
classe principale de l'application (classe main : SpringBootAplication).
2- Ensuite, Spring Boot configure les composants détectés en appliquant les auto-configurations et
les propriétés de configuration spécifiées. Les auto-configurations sont des classes qui détectent
automatiquement les bibliothèques et les frameworks présents dans le classpath et les
configurent en fonction des paramètres de configuration fournis. Les propriétés de configuration
peuvent être spécifiées dans un fichier [Link] ou [Link] ou bien via des
variables d'environnement.
3- Après la configuration des composants, Spring Boot initialise l'application en créant un contexte
d'application Spring. Ce contexte contient tous les composants de l'application ainsi que les
beans créés par les auto-configurations.
Le contexte d'application Spring créé par Spring Boot est généralement situé en mémoire dans la
JVM (Java Virtual Machine). Plus précisément, il est stocké dans une instance de la classe
ApplicationContext.
Par défaut, le contexte d'application est créé et géré par le conteneur d'inversion de contrôle
(IoC) de Spring, qui est intégré à Spring Boot.
BeanFactory est la superclasse de la ApplicationContext, qui est une extension de la BeanFactory
avec des fonctionnalités supplémentaires telles que la gestion des événements,
l'internationalisation, la gestion des transactions, etc.
La BeanFactory est responsable de la gestion des cycles de vie des beans, de la résolution des
dépendances et de l'injection des dépendances.
4- Enfin, Spring Boot lance le serveur web intégré et déploie l'application. Le serveur web intégré
est configuré automatiquement en fonction des composants détectés et des propriétés de
configuration spécifiées.
Une fois l'application lancée, elle est prête à traiter les requêtes entrantes. Les contrôleurs de
l'application sont mappés aux URL correspondantes et les services et les repositories sont prêts à
interagir avec les données.
1- @Configuration indique que la classe est une configuration Spring et peut contenir des méthodes
qui créent et configurent des beans.
2- @EnableAutoConfiguration permet à Spring Boot de configurer automatiquement les
composants de l'application en fonction du contexte d'exécution.
3- @ComponentScan permet à Spring de scanner le classpath pour trouver les composants de
l'application.
Spring Security : est un module de sécurité pour les applications Spring, qui fournit des fonctionnalités
de sécurité telles que l'authentification, l'autorisation et la protection contre les attaques.
Spring Security est intégré à Spring Boot et permet une configuration facile des fonctionnalités de
sécurité.
Il permet de configurer facilement des règles de sécurité personnalisées, d'authentifier les utilisateurs et
de les autoriser à accéder aux ressources de l'application, tout en offrant une protection contre les
attaques courantes.
1- Dépendance : Ajouter la dépendance Spring Security dans votre projet Spring Boot dans votre
fichier de configuration Maven.
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
2- Configuration : Ensuite, vous devez configurer Spring Security pour définir les règles
d'authentification et d'autorisation pour votre application, en créant une classe de configuration
et en l'annotant avec @EnableWebSecurity.
Cette classe de configuration peut être utilisée pour définir des règles de sécurité personnalisées
en utilisant des filtres et des intercepteurs.
3- Authentification : Spring Security prend en charge plusieurs méthodes d'authentification, telles
que l'authentification basée sur les formulaires, l'authentification basée sur les jetons et
l'authentification basée sur les certificats. Vous pouvez choisir la méthode d'authentification qui
convient le mieux à votre application.
4- Autorisation : Une fois que l'utilisateur est authentifié, Spring Security vérifie les autorisations
de l'utilisateur pour accéder aux ressources de l'application. Vous pouvez définir des règles
d'autorisation personnalisées en utilisant des annotations telles que @PreAuthorize et
@PostAuthorize.
@PreAuthorize et @PostAuthorize sont deux annotations de sécurité fournies par Spring
Security. Ces annotations permettent de contrôler l'accès aux méthodes de votre application en
fonction des rôles et des autorisations des utilisateurs.
- @PreAuthorize est une annotation utilisée pour spécifier une expression SpEL (Spring
Expression Language) qui doit être évaluée avant l'exécution d'une méthode. Si l'expression
renvoie true, la méthode peut être exécutée. Sinon, une exception d'accession est lancée.
- @PostAuthorize, quant à lui, est utilisé pour spécifier une expression SpEL qui doit être
évaluée après l'exécution d'une méthode. Si l'expression renvoie true, le résultat de la
méthode est renvoyé à l'appelant. Sinon, une exception d'accession est lancée.
5- Protection contre les attaques : Spring Security fournit également des fonctionnalités de
protection contre les attaques courantes telles que les attaques par injection SQL, les attaques
par Cross-Site Scripting (XSS) et les attaques par Cross-Site Request Forgery (CSRF).
Implémentation de Spring Security OAuth2 pour utilizer les jetons web (JWT)
OAuth 2.0 est un protocole d'autorisation ouvert qui permet à une application tierce d'obtenir un accès
limité à des ressources protégées au nom d'un utilisateur, sans avoir à partager ses identifiants de
connexion.
Un JWT (JSON Web Token) est un standard ouvert (RFC 7519) qui permet de représenter des
revendications (claims) de manière sécurisée entre deux parties.
Un JWT est souvent utilisé pour gérer l'authentification et l'autorisation dans les applications web.
Lorsqu'un utilisateur se connecte à une application, le serveur génère un JWT contenant les informations
d'authentification de l'utilisateur (par exemple son nom d'utilisateur et ses rôles).
Le client peut ensuite inclure ce token dans chaque requête envoyée au serveur pour prouver qu'il est
autorisé à accéder à certaines ressources.
Le serveur peut alors vérifier la signature du token pour s'assurer qu'il est authentique et qu'il a été émis
par un serveur de confiance.
Spring Data
Spring Data est un projet de la communauté Spring qui fournit une abstraction de haut niveau pour
interagir avec différents types de stockage de données, tels que les bases de données relationnelles, les
bases de données NoSQL, les services de stockage en nuage, etc.
Spring Data comprend plusieurs sous-projets, chacun se concentrant sur un type de stockage de données
différent.
Spring Data JPA : Il fournit une couche d'abstraction au-dessus de JPA pour faciliter l'accès aux bases de
données relationnelles.
Spring Data MongoDB : Il fournit une couche d'abstraction pour travailler avec MongoDB, une base de
données NoSQL orientée document.
Spring Data JDBC : Il fournit une couche d'abstraction pour travailler avec des bases de données
relationnelles en utilisant JDBC.
Spring Data Redis : Il fournit une couche d'abstraction pour travailler avec Redis, une base de données
NoSQL de type clé-valeur.
Spring Data Elasticsearch : Il fournit une couche d'abstraction pour travailler avec Elasticsearch, un moteur
de recherche distribué.
Abstraction de persistance de données : Spring Data JPA fournit une couche d'abstraction pour interagir
avec des bases de données relationnelles en utilisant Java Persistence API (JPA).
Repositories : Spring Data JPA permet de créer facilement des repositories pour interagir avec les données
stockées dans une base de données relationnelle.
Création automatique de requêtes : Spring Data JPA utilise la convention de nommage pour générer
automatiquement les requêtes pour les méthodes de repository.
Pagination : Spring Data JPA fournit des fonctionnalités de pagination pour récupérer les résultats de
requêtes par blocs.
Transactions : Spring Data JPA fournit des fonctionnalités de gestion des transactions pour garantir
l'intégrité des données dans une base de données.
Recherche en texte intégral : Spring Data JPA permet d'effectuer des recherches en texte intégral sur les
données stockées dans une base de données.
Optimisation des requêtes : Spring Data JPA optimise les requêtes pour améliorer les performances et
réduire la charge sur la base de données.
Les transactions en Spring Data JPA : sont gérées à l'aide de l'annotation @Transactional
Cette annotation est utilisée pour déclarer que les méthodes annotées doivent être exécutées dans une
transaction.
Cela garantit que toutes les opérations de mise à jour de la base de données effectuées dans cette
méthode sont exécutées dans une transaction unique. Si l'une de ces opérations échoue, la transaction
est automatiquement annulée (rollback), ce qui garantit l'intégrité de la base de données.
En outre, il est important de noter que les transactions sont gérées au niveau des méthodes dans Spring
Data JPA. Cela signifie que si une méthode de service appelle plusieurs méthodes de repository, chaque
méthode de repository sera exécutée dans sa propre transaction. Cela permet d'optimiser les
transactions et de minimiser les verrous sur la base de données.
Les requêtes personnalisées définies à l'aide de l'annotation @Query sont vérifiées au moment de la
compilation, ce qui permet de détecter les erreurs de syntaxe et de noms de colonnes à temps. De plus,
Spring Data JPA peut générer automatiquement des requêtes à partir des noms de méthode de
repository, mais dans certains cas, il peut être nécessaire d'utiliser l'annotation @Query pour écrire des
requêtes plus complexes.
Hibernate : Il s'agit d'un framework Java, open-source, léger et outil ORM (Object Relational Mapping)
pour le langage Java
C’est un outil ORM (Object-Relational Mapping) utilisé pour enregistrer (persister) les objets Java dans le
système de base de données relationnelle, en minimisant la quantité du code nécessaire.
Il est utilisé pour enregistrer les objets Java dans le système de base de données relationnelle.
Hibernate est l’ORM par défaut de SpringBoot. Ce dernier fournit une intégration étroite avec Hibernate
pour faciliter la configuration et l’utilisation de l’ORM.
Hibernate est une implémentation de la spécification de JPA, ce qui signifie qu’il implémente toutes les
fonctionnalités de JPA et fournit également des fonctionnalités supplémentaires qui ne sont pas incluses
dans JPA ➔ Hibernate est plus riche en fonctionnalités que JPA.
Les indexes de la BD : ils ont des structures de BD, utilisés pour accélérer les opérations de recherche et
de tri dans une BD
Un index est essentiellement une liste ordonnée de valeurs de colonne avec un pointeur vers
l’emplacement de chaque valeur dans la table de BD
➔ L’utilisation d’un index permet de trouver rapidement les lignes qui répondent à une condition de
recherche spécifique plutôt que de parcourir toute la table à la recherche des lignes appropriées.
SQL Joins :
En SQL, une jointure (ou "JOIN" en anglais) est utilisée pour combiner des données provenant de deux
tables ou plus, en utilisant une condition de correspondance spécifique. Voici les types de jointures les
plus couramment utilisées :
Jointure interne (INNER JOIN) : renvoie uniquement les enregistrements qui ont une correspondance
dans les deux tables.
Jointure externe gauche (LEFT JOIN) : renvoie tous les enregistrements de la table de gauche et les
enregistrements correspondants de la table de droite.
Jointure externe droite (RIGHT JOIN) : renvoie tous les enregistrements de la table de droite et les
enregistrements correspondants de la table de gauche.
Jointure externe complète (FULL OUTER JOIN) : renvoie tous les enregistrements de la table de gauche et
de la table de droite, ainsi que les enregistrements correspondants.
Il existe également d'autres types de jointures moins couramment utilisées, comme la jointure croisée
(CROSS JOIN) et la jointure auto-interne (SELF JOIN).
Annotations :
@Id : cette annotation est utilisée pour marquer une propriété d'entité comme la clé primaire de la table
de base de données correspondante.
@GeneratedValue : cette annotation est utilisée pour spécifier la façon (la stratégie) dont la valeur de la
clé primaire est générée automatiquement lors de la création d'une nouvelle entité.
Il y a des annotations permettent de spécifier comment les entités sont associées les unes aux autres
dans la base de données :
@OneToOne : Cette annotation est utilisée pour définir une relation un-à-un entre deux entités. Par
exemple, si une entité Employee a une référence à une autre entité Address.
@OneToMany : Cette annotation est utilisée pour définir une relation un-à-plusieurs entre deux entités.
Par exemple, si une entité Department a plusieurs entités Employee.
@OneToMany(mappedBy = "department", cascade = [Link])
private List<Employee> employees;
@ManyToOne : Cette annotation est utilisée pour définir une relation plusieurs-à-un entre deux entités.
Par exemple, si plusieurs entités Employee sont associées à une seule entité Department.
@ManyToOne
@JoinColumn(name = "department_id")
private Department department;
@ManyToMany : Cette annotation est utilisée pour définir une relation plusieurs-à-plusieurs entre deux
entités. Par exemple, si plusieurs entités Employee sont associées à plusieurs entités Project, on peut
utiliser l'annotation @ManyToMany pour spécifier cette relation.
@ManyToMany
@JoinTable(
name = "employee_project",
joinColumns = @JoinColumn(name = "employee_id"),
inverseJoinColumns = @JoinColumn(name = "project_id")
)
private List<Project> projects;
@ManyToMany(mappedBy = "projects")
private List<Employee> employees;
Lazy Loading:
Lorsqu’une entité est chargée à partir de la base de données, ses associations ne sont pas chargées
immédiatement. Au lieu de cela, les associations ne sont chargées que lorsque l'application accède directement à
ces associations. ➔ Seulement les références sur ces associations sont chargées.
• Utilisé pour les associations qui sont rarement ou jamais utilisées.
Eager Loading :
Lorsqu’une entité est chargée à partir de la base de données, toutes ses associations sont également chargées en
mémoire.
• Utilisé pour les associations qui sont fréquemment utilisées.
En Java Persistence API (JPA), CascadeType est une énumération qui définit les types d'opérations qui doivent être
propagées d'une entité à une autre lorsque certaines actions sont effectuées sur une entité.
1- [Link] : Propage toutes les opérations : persist, merge, remove, refresh et detach.
2- [Link] : Propage l'opération persist pour ajouter une entité nouvellement créée à la base
de données.
3- [Link] : Propage l'opération merge pour mettre à jour une entité existante dans la base de
données.
4- [Link] : Propage l'opération remove pour supprimer une entité de la base de données.
5- [Link] : Propage l'opération refresh pour actualiser les valeurs d'une entité à partir de la
base de données.
6- [Link] : Propage l'opération detach pour détacher une entité de la session JPA.
En JPA, la méthode flush() est utilisée pour synchroniser les modifications en attente dans le contexte de
persistance avec la base de données.
La méthode flush() force la synchronisation des modifications dans le contexte de persistance, ce qui signifie que
les requêtes d'écriture correspondantes seront exécutées immédiatement, mais la transaction n'est pas encore
validée. Cela peut être utile lorsque vous souhaitez forcer l'exécution des requêtes d'écriture avant d'effectuer
d'autres opérations ou avant de valider la transaction.
D'autre part, la méthode saveAndFlush() est une méthode spécifique à Spring Data JPA qui combine les opérations
de sauvegarde (création ou mise à jour) et de synchronisation dans une seule méthode. Lorsque vous appelez
saveAndFlush(entity), l'entité spécifiée est enregistrée en utilisant la méthode save(), puis la méthode flush() est
appelée pour synchroniser immédiatement les modifications avec la base de données.
Spring AOP
Spring AOP (Aspect-Oriented Programming) est une fonctionnalité de Spring Framework qui permet de
séparer les préoccupations transversales, telles que la sécurité, la journalisation et la gestion des
transactions, de la logique métier principale d'une application.
Cette approche permet de modulariser le code de manière plus efficace et de faciliter la maintenance de
l'application.
La programmation orientée aspect (AOP) complète la programmation orientée objet (POO) en offrant une
autre façon de penser la structure du programme. L'unité clé de la modularité dans la POO est la classe,
alors que dans l'AOP l'unité de la modularité est l'aspect.
Pour ce faire, il ajoute un code supplémentaire au code existant sans modifier le code lui-même.
AOP permet d'ajouter dynamiquement des logiques et des traitements autour, avant ou après d’une
méthode.
Les aspects peuvent être appliqués à des classes, des méthodes ou même des paramètres de méthode.
<dependencies>
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
</dependencies>
@Target : est une annotation utilisée en Java pour spécifier les types d'éléments sur lesquels une autre
annotation peut être utilisée. En d'autres termes, elle permet de limiter les endroits où une annotation
peut être appliquée.
[Link] : l'annotation peut être appliquée à une classe, une interface ou une énumération.
@Retention est une autre annotation en Java qui est utilisée pour spécifier la durée de vie d'une autre
annotation. Plus précisément, elle permet de définir à quel moment une annotation sera conservée, ou
"retenue", dans le code. ➔ Indique simplement si l’annotation sera disponible pour la JVM lors de
l’exécution ou non.
[Link] : les annotations sont conservées uniquement dans le code source et sont
ignorées lors de la compilation.
[Link] : les annotations sont conservées dans le fichier de classe mais sont ignorées lors
de l'exécution. C'est la valeur par défaut de @Retention.
[Link] : les annotations sont conservées dans le fichier de classe et peuvent être lues
à l'exécution en utilisant des techniques de réflexion.
➔Tout ce que c’est, est une classe annotée avec @Aspect : cest le module qui résume notre
préoccupation transversale.
/**
* This component aims to verify the user identity before invoke
the exposed API.
*/
@Aspect
@Component
@Order(0)
public class SecureApiHandle {
@Before("@within([Link])")
public void checkPermission() {
if ([Link]([Link]())) {
throw new UnauthorizedRequestException("Inactive
User");
}
DeviceDto deviceDto =
[Link]([Link](), deviceId);
if (deviceDto == null) {
throw new DeviceNotFoundException();
}
if ([Link]() == null) {
throw new DeviceNotValidException();
}
if
(![Link]().equalsIgnoreCase([Link]
ceStatus().name())) {
throw new DeviceNotValidException();
}
[Link]([Link]());
[Link]([Link]());
}
}
Il s’agit essentiellement de la classe dans laquelle nous avons implémenter la logique que nous voulons
que notre app personnalisée injecte.
Maven est un outil de gestion et d'automatisation de développement et production des projets Java.
Maven est utilisé pour automatiser l'intégration continue lors d'un développement de logiciel.
Maven utilise la notion de portée (scope) pour préciser comment la dépendance sera utilisée.
• Compile : la dépendance est utilisable par toutes les phases et à l'exécution. C'est le scope par
défaut.
• Provided : la dépendance est utilisée pour la compilation mais elle ne sera pas déployée car elle
est considérée comme étant fournie par l'environnement d'exécution. C'est par exemple le cas des
API fournies par un serveur d'applications.
• Runtime : la dépendance n'est pas utile pour la compilation mais elle est nécessaire à l'exécution.
C'est par exemple le cas des pilotes JDBC
• Test : la dépendance n'est utilisée que lors de la compilation et de l'exécution des tests. C'est par
exemple le cas pour la bibliothèque utilisée pour les tests unitaires (JUnit ou TestNG pas exemple)
ou pour les doublures (Easymock, Mockito, ...)
Maven gère automatiquement les dépendances ce qui facilite la résolution et la récupération des
bibliothèques.
Le contrôle de version (version control), également connu sous le nom de contrôle de source (source
control), c’est une pratique consistant à suivre et à gérer les modifications apportées au code logiciel.
Système de contrôle de révision rapide, évolutif et distribué. C’est un système de contrôle de version
distribué gratuit et open-source conçu pour tout gérer, des petits aux très grands projets, avec rapidité et
efficacité
GitLab : logiciel de gestion Git open source auto-hébergé. Il propose une gestion de référentiel git, des
révisions de code, un suivi des problèmes, des flux d'activité et des wikis.
Git est la véritable technologie de contrôle de code source, et GitLab est l'interface utilisateur Web ou
l'interface de Git.
Git peut-être classé comme un outil dans la catégorie "Système de contrôle de version", tandis que
GitLab est regroupé sous "Collaboration de code et contrôle de version"
Docker est une plateforme open-source populaire pour la virtualisation légère et la gestion des
conteneurs. Il permet d'emballer des applications et leurs dépendances dans des conteneurs légers et
portables, offrant ainsi une grande flexibilité et une meilleure gestion des ressources.
Le concept central de Docker repose sur les conteneurs. Un conteneur est une unité d'exécution qui
regroupe une application et toutes ses dépendances, y compris les bibliothèques, les fichiers binaires, les
variables d'environnement, etc. Ces conteneurs sont isolés les uns des autres et fournissent un
environnement cohérent et reproductible pour l'exécution d'applications.
Docker est un excellent outil pour exécuter des bases de données, des serveurs de cache et d'autres
services sans alourdir votre ordinateur portable avec l'installation et la configuration de ces logiciels
individuellement.
Isolation et portabilité : Avec Docker, vous pouvez créer des conteneurs pour chaque service, tels que la
base de données, Redis et Keycloak. Chaque conteneur sera isolé, ce qui signifie que les dépendances et
les configurations spécifiques à chaque service seront encapsulées dans le conteneur.
Facilité de configuration : Docker permet de configurer les conteneurs à l'aide de fichiers Dockerfile ou
Docker Compose. Ces fichiers décrivent les dépendances, les configurations et les paramètres du service.
Vous pouvez ainsi spécifier les versions de logiciels souhaitées, les ports à exposer, les volumes de
données à monter, etc. Il vous suffit de créer une fois ces fichiers de configuration et vous pourrez les
utiliser pour exécuter les services sur n'importe quelle machine.
Facilité de déploiement
Gestion des ressources : Docker vous permet de définir les ressources allouées à chaque conteneur,
telles que la mémoire, le processeur et l'espace disque. Vous pouvez ajuster ces paramètres en fonction
des exigences de chaque service. Cela vous aide à optimiser l'utilisation des ressources de votre
ordinateur portable et à éviter de les surcharger.
Exception Handling
L'annotation @ControllerAdvice est utilisée pour définir un composant qui s'applique de manière globale
à tous les contrôleurs de votre application. Elle permet de capturer les exceptions levées par les
contrôleurs ou les méthodes annotées @RequestMapping, afin de fournir une réponse cohérente et
personnalisée en cas d'erreur.
Par exemple, vous pouvez utiliser @ExceptionHandler pour gérer les exceptions levées par une méthode
et renvoyer une réponse HTTP 404 ou 500 personnalisée.
Voici les étapes générales de la gestion des exceptions dans Spring Boot :
1- Définir les exceptions que vous souhaitez gérer : Pour définir les exceptions que vous souhaitez
gérer, vous pouvez créer une classe personnalisée qui étend la classe Exception de base ou
l'une de ses sous-classes (RuntimeException par exemple).
3- Utiliser les annotations de Spring Boot : Spring Boot fournit plusieurs annotations qui vous
permettent de spécifier comment les exceptions doivent être gérées dans votre application. Par
exemple, vous pouvez utiliser l'annotation @ExceptionHandler pour spécifier la méthode à
appeler lorsque cette exception est levée.
4- Personnaliser les messages d'erreur : Vous pouvez personnaliser les messages d'erreur renvoyés
par votre application en utilisant des fichiers de propriétés. Vous pouvez définir des messages
d'erreur pour chaque exception que vous avez définie et spécifier la langue dans laquelle ces
messages doivent être renvoyés.
L'annotation @ResponseStatus est une annotation de Spring Boot qui permet de spécifier la réponse
HTTP à renvoyer en cas d'occurrence d'une exception particulière. Elle est généralement utilisée en
conjonction avec l'annotation @ExceptionHandler pour personnaliser les réponses d'erreur renvoyées
par une méthode de contrôleur lorsqu'une exception est levée.
➔En utilisant @ResponseStatus, vous pouvez spécifier le code de réponse HTTP et le message à
renvoyer lorsque l'exception spécifiée est levée. Par exemple, vous pouvez utiliser cette annotation pour
renvoyer une réponse HTTP 404 (Not Found) lorsque l'exception ResourceNotFoundException est levée.
Test Unitaires
Les tests unitaires sont une pratique courante en programmation informatique qui consiste à écrire des
tests automatisés pour vérifier le fonctionnement de petits morceaux de code, appelés "unités", tels que
des fonctions, des méthodes ou des classes. Les tests unitaires sont importants car ils permettent de
s'assurer que chaque unité de code fonctionne correctement de manière isolée avant d'être intégrée
dans l'ensemble de l'application.
- JUnit : JUnit est un framework de test unitaire pour Java qui est largement utilisé dans le
développement d'applications Spring Boot.
JUnit fournit des annotations telles que @Test, @Before, et @After pour faciliter l'écriture
de tests unitaires.
Spring Boot fournit des fonctionnalités d'intégration pour JUnit, telles que
@RunWith([Link]) et @SpringBootTest. Ces annotations permettent de
configurer le contexte Spring pour les tests et de simplifier la mise en place de tests
unitaires en utilisant Spring.
- Mockito : est une bibliothèque Java très populaire pour la création d'objets simulés (ou
mock) dans le cadre de tests unitaires.
Exemple :
@MockBean est une annotation fournie par Spring Boot qui permet de créer un objet simulé (mock)
pour une dépendance spécifique d'une classe à tester dans un test unitaire.
En utilisant @MockBean, vous pouvez remplacer une instance réelle d'une dépendance par un objet
simulé dans le contexte de Spring, sans avoir à modifier le code de production
@InjectMocks pour injecter automatiquement l'objet simulé de UserRepository dans l'objet UserService
que nous testons.
Dans la méthode de test testGetUserById(), nous utilisons la méthode when() de Mockito pour définir le
comportement simulé de la méthode findById() de UserRepository .
➔ La principale différence entre @MockBean et @Mock est que @MockBean est spécifique à Spring
Boot et permet de créer des objets simulés dans le contexte de l'application Spring Boot, tandis que
@Mock est plus général et peut être utilisé dans n'importe quelle application Java.
Enfin, nous vérifions que l'objet User renvoyé par getUserById() a les bonnes propriétés en utilisant la
méthode assertEquals() de JUnit.
AssertJ est une bibliothèque qui fournit des assertions supplémentaires pour les tests unitaires en Java.
Les développeurs peuvent utiliser AssertJ pour effectuer des vérifications plus précises sur les résultats
des tests.
Voici les étapes pour écrire un test unitaire en Spring Boot :
Sélectionner une classe à tester : Vous devez commencer par choisir une classe à tester. Cette classe
peut être une classe de service, une classe de contrôleur, ou une autre classe que vous souhaitez tester.
Créer un fichier de test : Créez un fichier Java dans le même package que la classe à tester et suffixez-le
avec "Test". Par exemple, si vous voulez tester la classe UserService, vous pouvez créer un fichier de test
appelé UserServiceTest.
Annoter la classe de test : Annoter la classe de test avec @RunWith([Link]) pour indiquer
que vous souhaitez utiliser Spring pour exécuter le test.
Injecter les dépendances : Annoter les propriétés de la classe de test qui doivent être injectées avec
@Autowired pour permettre à Spring d'injecter automatiquement les dépendances.
Écrire la méthode de test : Écrire une méthode de test en utilisant l'annotation @Test. Dans cette
méthode, vous pouvez appeler les méthodes de la classe à tester et effectuer des assertions pour vérifier
que le comportement de la méthode est correct.
Exécuter le test : Exécuter le test en utilisant une option telle que "Run As JUnit Test" dans Eclipse ou en
exécutant la commande "mvn test" dans la ligne de commande. Les résultats des tests seront affichés
dans la console ou dans l'IDE.
Vérifier les résultats : Vérifier les résultats du test et corriger les erreurs éventuelles. Si le test réussit,
vous pouvez alors passer à l'étape suivante.
Répéter le processus : Répéter ce processus pour chaque classe que vous souhaitez tester.
En résumé, écrire un test unitaire en Spring Boot implique de créer un fichier de test, annoter la classe
de test avec @RunWith([Link]), injecter les dépendances avec @Autowired, écrire une
méthode de test en utilisant @Test, exécuter le test et vérifier les résultats. En suivant ces étapes, vous
pouvez écrire des tests unitaires efficaces pour garantir la qualité et la fiabilité de votre code.
Design patterns
Ils sont des solutions éprouvées aux problèmes de conception récurrents rencontrés lors du
développement des logiciels, pour permettre une utilisation facile par les développeurs.
Singleton : Le Singleton est un design pattern qui garantit qu'une classe ne possède qu'une seule
instance et fournit un point d'accès global à cette instance. Il est souvent utilisé pour des classes
qui doivent être instanciées une seule fois, comme les gestionnaires de connexion à une base de
données.
Builder : Le Builder est un design pattern utilisé pour créer des objets complexes étape par
étape. Il permet de séparer le processus de construction d'un objet de sa représentation, offrant
ainsi plus de flexibilité et de contrôle sur la création d'objets complexes. C'est souvent utilisé
pour créer des objets immuables ou pour simplifier la création d'objets avec de nombreux
paramètres.
Factory : C’est un patron de conception de création qui permet de déléguer la création d'objets
à une classe dédiée, appelée la Factory. Il permet de résoudre le problème de la création
d'objets sans avoir à spécifier la classe exacte de l'objet qui sera créé. ➔ Créer un objet dont le
type dépend du contexte
Prototype : Le design pattern Prototype est utilisé pour créer de nouvelles instances d'objets en
utilisant un modèle d'instance existant, plutôt que de créer de nouvelles instances à partir de
zéro. Cela permet de créer des copies d'objets existants tout en évitant la complexité liée à leur
initialisation.
Le Prototype est utile lorsque la création d'objets est coûteuse en termes de performances ou
de ressources, ou lorsque des variations d'un objet de base sont nécessaires sans avoir à
recourir à une hiérarchie de classes complexe
Adapter : L'Adapter est un design pattern utilisé pour connecter deux interfaces incompatibles.
Il permet à des classes aux interfaces différentes de travailler ensemble en fournissant un
wrapper qui convertit l'interface d'une classe en une autre interface attendue. Cela facilite la
réutilisation de classes existantes qui ne sont pas directement compatibles.
3- Design Pattern de comportement :
Fournissent des mécanismes pour organiser le comportement des objets et les intéractions
entre eux.
Observer : L'Observer est un design pattern utilisé pour mettre en place une communication de
type "publier/souscrire" entre objets. Il permet à un objet, appelé le sujet, de notifier
automatiquement ses observateurs lorsque son état change. Cela permet une conception
souple et découplée, où les observateurs peuvent réagir aux changements de l'état du sujet de
manière appropriée.
Strategy : Le Strategy est un design pattern qui permet de définir une famille d'algorithmes
interchangeables et de les encapsuler de manière à ce qu'ils puissent être utilisés de manière
interchangeable. Cela permet de déléguer le choix de l'algorithme spécifique à utiliser à
l'exécution, offrant ainsi une plus grande flexibilité et facilitant les modifications ou extensions
ultérieures de l'application.
Principes SOLID
1- Single Responsibility Principle (SRP) : Ce principe stipule qu'une classe ne doit avoir qu'une seule
responsabilité. En d'autres termes, une classe doit être conçue pour effectuer une seule tâche
bien précise.
Pour implémenter SRP en Java, il suffit de s'assurer que chaque classe ne contient qu'une seule
responsabilité. Par exemple, une classe qui gère la connexion à une base de données devrait
avoir pour seule responsabilité la gestion de la connexion, et ne pas contenir d'autres
fonctionnalités telles que la récupération de données.
2- Open/Closed Principle (OCP) : Ce principe stipule que les entités logicielles (classes, modules,
etc.) doivent être ouvertes à l'extension mais fermées à la modification. En d'autres termes, il
devrait être possible d'ajouter de nouvelles fonctionnalités à une entité logicielle sans avoir à la
modifier.
Pour implémenter OCP en Java, il est important de concevoir des classes qui peuvent être
étendues sans être modifiées. Par exemple, une classe qui définit une opération mathématique
devrait pouvoir être étendue pour prendre en charge de nouveaux types de données sans avoir
à modifier sa logique existante.
3- Liskov Substitution Principle (LSP) : Ce principe stipule que les sous-classes doivent pouvoir être
utilisées comme des instances de leur classe de base sans que cela ne provoque de
comportements indésirables dans le programme. En d'autres termes, les sous-classes ne doivent
pas violer le contrat de comportement défini par leur classe de base.
Pour implémenter LSP en Java, il est important de concevoir des sous-classes qui peuvent être
utilisées comme des instances de leur classe de base sans causer de comportements
indésirables. Par exemple, si une classe dépend d'une interface Animal qui définit une méthode
speak(), toutes les sous-classes d'Animal devraient être en mesure de répondre à cette méthode
sans causer de problèmes.
4- Interface Segregation Principle (ISP) : Ce principe stipule qu'il vaut mieux avoir plusieurs
interfaces spécialisées plutôt qu'une seule interface générale. En d'autres termes, les interfaces
ne doivent contenir que les méthodes nécessaires à leur utilisation par les clients.
Pour implémenter ISP en Java, il est important de créer des interfaces spécialisées qui ne
contiennent que les méthodes nécessaires à leur utilisation par les clients.
5- Dependency Inversion Principle (DIP) : Ce principe stipule que les modules de haut niveau ne
doivent pas dépendre des modules de bas niveau. Au lieu de cela, les deux niveaux devraient
dépendre d'abstractions. En d'autres termes, les classes de haut niveau ne devraient pas
dépendre directement des classes de bas niveau, mais plutôt des interfaces qui définissent les
fonctionnalités nécessaires.
La principale différence entre Spring WebFlux et les REST APIs réside dans leur approche de la gestion
des requêtes et des réponses.
Paradigme de programmation :
Spring WebFlux : Spring WebFlux adopte une approche réactive et non bloquante pour la gestion des
requêtes. Il utilise des flux réactifs (Flux et Mono) pour manipuler les données de manière asynchrone,
ce qui permet de gérer un grand nombre de requêtes simultanées de manière efficace.
REST APIs : Les REST APIs, en général, utilisent une approche traditionnelle basée sur le modèle
requête/réponse synchrone. Chaque requête bloque le thread d'exécution jusqu'à ce qu'elle reçoive une
réponse.
Modèle de programmation :
Spring WebFlux : WebFlux utilise le modèle de programmation fonctionnelle. Vous construisez des
pipelines de traitement en utilisant des fonctions lambda et des opérations fonctionnelles.
REST APIs : Les REST APIs utilisent généralement le modèle de programmation orienté objet. Vous
définissez des classes de contrôleur annotées avec des annotations telles que @RestController et
@RequestMapping pour définir les points de terminaison et les méthodes pour gérer les requêtes.
Performances :
Spring WebFlux : En utilisant une architecture réactive et non bloquante, WebFlux est plus adapté pour
les applications qui nécessitent une haute performance, une évolutivité et une gestion efficace des
charges de travail élevées.
REST APIs : Les REST APIs peuvent également être performantes, mais elles peuvent atteindre leurs
limites lorsqu'il s'agit de gérer des charges de travail importantes ou de nombreux appels simultanés.
L'injection de dépendances (dependency injection) est une fonctionnalité fondamentale de Spring qui
permet de gérer les dépendances entre les différents composants d'une application. Avec
@SpringBootApplication, l'injection de dépendances est automatiquement prise en charge et vous
pouvez utiliser des annotations telles que @Autowired pour injecter des dépendances dans vos classes.
Un classloader est un objet qui charge dynamiquement et initialise des classes et interfaces Java requises
par la JVM lors de l'exécution d'une application. Un classloader hérite de la classe [Link].
• ModelMapper est une bibliothèque Java qui facilite le mappage d'objets entre différents
modèles de données. Elle permet de transférer des données d'un objet source vers un objet
cible en utilisant des règles de correspondance prédéfinies ou personnalisées
• MapStruct est une bibliothèque de mappage d'objets générée par annotation. Elle génère
automatiquement le code de mappage à la compilation, ce qui offre de bonnes performances.
Pour l'utiliser, vous devez définir des interfaces avec des méthodes de mappage et annoter ces
méthodes avec des annotations spécifiques de MapStruct. Le code de mappage est généré
automatiquement lors de la compilation. Exemple :
• Les projections vous permettent de spécifier les propriétés spécifiques que vous souhaitez
récupérer à partir d'une entité, plutôt que de récupérer toutes les propriétés de l'entité
complète. Cela peut être utile lorsque vous avez besoin de récupérer uniquement un sous-
ensemble de propriétés d'une entité pour des performances optimisées ou pour éviter de
transmettre des données inutiles.
La principale différence entre Feign et REST réside dans leur approche pour effectuer des appels de
services. REST (Representational State Transfer) est un style architectural qui définit un ensemble de
principes pour construire des services web. Il se base sur les méthodes HTTP (GET, POST, PUT, DELETE) et
les formats de données standard (JSON, XML) pour communiquer avec les services.
Feign, quant à lui, est une bibliothèque qui facilite l'appel des services REST. Elle s'intègre avec Spring
pour simplifier la configuration et l'utilisation des clients REST. Au lieu d'écrire manuellement le code
pour effectuer des requêtes HTTP, Feign permet de déclarer des interfaces avec des annotations qui
décrivent les requêtes et les réponses attendues. Feign se charge ensuite de générer automatiquement
le code nécessaire pour effectuer les appels HTTP correspondants.