Blog ENI : Toute la veille numérique !
🐠 -25€ dès 75€ 
+ 7 jours d'accès à la Bibliothèque Numérique ENI. Cliquez ici
Accès illimité 24h/24 à tous nos livres & vidéos ! 
Découvrez la Bibliothèque Numérique ENI. Cliquez ici
  1. Livres et vidéos
  2. Java Spring
  3. Spring Boot
Extrait - Java Spring Le socle technique des applications Jakarta EE (4e édition)
Extraits du livre
Java Spring Le socle technique des applications Jakarta EE (4e édition) Revenir à la page d'achat du livre

Spring Boot

Introduction

Depuis quelques années, de nombreux investissements ont été faits dans Spring Boot pour apporter une grande facilitation vis-à-vis de l’utilisation de l’écosystème basé sur le framework Spring.

Spring boot est principalement une classe SpringApplication qui fournit un moyen pratique d’amorcer une application Spring démarrée à partir d’une méthode main(). Dans de nombreuses situations, nous pouvons déléguer à la méthode statique SpringApplication.run() le soin de démarrer l’application. C’est aussi une mécanique d’auto-configuration en fonction des dépendances qui sont liées à l’application. Cette application peut être standalone, un serveur, un Batch...

Spring Boot est une application générique qui permet de faire facilement des applications standards. Nous pouvons concevoir rapidement des applications web, batch ou microservices, en nous appuyant sur des implémentations par défaut que l’on peut personnaliser. Pour les applications web/web services, Spring permet par exemple de créer des applications autonomes pouvant embarquer un conteneur Tomcat et il est possible de choisir Jetty ou Undertow ou une des autres implémentations disponibles comme substitut pour le conteneur de servlet interne ou de choisir d’utiliser...

Configuration des exemples

Nous allons décrire quelques exemples d’utilisation.

1. Configuration Maven pour la version 1.5 de Spring Boot

<parent>  
 <groupId>org.springframework.boot</groupId>  
 <artifactId>spring-boot-starter-parent</artifactId>  
 <version>1.5.22.RELEASE</version>  
</parent>  
<dependencies>  
 <dependency>  
 <groupId>org.springframework.boot</groupId>  
 <artifactId>spring-boot-starter-web</artifactId>  
 </dependency>  
</dependencies> 

2. Configuration Maven pour la version 2 de Spring Boot

<parent>  
 <groupId>org.springframework.boot</groupId>  
 <artifactId>spring-boot-starter-parent</artifactId>  
 <version>2.6.6.RELEASE</version>  
</parent>  
<dependencies>  
 <dependency>  
 <groupId>org.springframework.boot</groupId>  
 <artifactId>spring-boot-starter-web</artifactId>  
 </dependency>  
</dependencies>  
[...]  
 
<build>  
  <plugins>  
    <plugin>  
      <groupId>org.springframework.boot</groupId>  
      <artifactId>spring-boot-maven-plugin</artifactId>...

L’auto-configuration Spring Boot

L’annotation @EnableAutoConfiguration est une composition des annotations @Configuration, d’un jeu d’annotations @Conditional qui configure en fonction des annotations @ConditionalOnClass et @ConditionalOnMissing et qui tient compte des classes trouvées dans le classpath.

Le service discovery permet de charger au runtime des implémentations d’un service en utilisant les factories. Ces dernières sont chargées via la classe SpringFactoryLoader qui récupère une liste de factories par le nom ou le type de la classe.

Spring Boot détecte la présence du fichier META-INF/spring.factories qui contient la clé :

org.springframework.boot.autoconfigure.EnableAutoConfiguration=  
fr.eni.spring5.autoconfigure.LibXAutoConfiguration,  
fr.eni.spring5.autoconfigure.LibXWebAutoConfiguration 

Ce fichier a sa correspondance dans Spring qui contient plus d’une centaine de lignes d’auto-configuration : spring-boot/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories. La factory a plus de cent lignes qui contiennent les mêmes types de clé que celle mentionnée ci-dessus.

La configuration automatique des Beans Spring

L’auto-configuration de Spring Boot essaie de configurer d’elle-même l’application à partir des dépendances des jars ajoutés....

Les starters

Les starters sont des dépendances qui ajoutent de l’auto-configuration à l’application basée sur Spring Boot. L’utilisation d’un starter permet d’indiquer que l’on veut ajouter une fonctionnalité à l’application et qu’on laisse au framework le soin de compléter notre configuration. Pour choisir la version du conteneur, il suffit de choisir le bon starter.

Voici une liste de starters. Certains starters sont décrits plus en détail dans les sections suivantes. La liste est plutôt longue :

1. Les starters courants

Starter

Utilité

spring-boot-starter

C’est le starter central incluant le support de l’auto-configuration, le logging et le Yaml. Il sera toujours présent.

spring-boot-starter-aop

Starter pour la programmation orienté aspect (AOP) avec Spring AOP et AspectJ.

spring-boot-starter-batch

Starter pour utiliser Spring Batch.

spring-boot-starter-cache

Starter pour utiliser le support de cache.

spring-boot-starter-jdbc

Starter pour utiliser JDBC avec le pool de connexions JDBC Tomcat.

spring-boot-starter-jersey

Starter pour construire des applications web RESTful en utilisant JAX-RS et Jersey comme alternative à spring-boot-starter-web.

spring-boot-starter-security

Starter pour utiliser Spring Security.

spring-boot-starter-test

Starter pour tester les applications Spring Boot avec JUnit, Hamcrest et Mockito.

spring-boot-starter-validation

Starter pour utiliser Java Bean Validation avec Hibernate Validator.

spring-boot-starter-web

Starter pour construire des applications web qui utilisent Spring MVC, en incluant les applications RESTful. Utilise Tomcat comme conteneur de servlets embarqué.

spring-boot-starter-web-services

Starter pour utiliser Spring Web Services.

spring-boot-starter-websocket

Starter pour construire des applications utilisant les WebSockets.

spring-boot-starter-logging

Starter pour logger avec Logback. C’est un starter par défaut.

spring-boot-starter-tomcat

Starter pour utiliser Tomcat comme conteneur de servlets embarqué. C’est le conteneur de servlets par défaut.

spring-boot-starter-web

Starter pour la fabrication d’outils destinés à la production ou à l’exploitation.

spring-boot-starter-actuator

Starter pour utiliser Spring Boot’s Actuator qui fournit une solution clé en main pour...

Spring MVC

Spring MVC avec Spring Boot utilise les serveurs suivants :

Serveur

Servlet Version

Tomcat 9

4.0

Jetty 9.4

3.1

Jetty 10.0

4.0

Undertow 2.0

4.0

Personnalisation de la bannière

Au lancement de l’application Spring Boot, il y a l’affichage d’une bannière dans la log. Cette bannière est personnalisable. Il suffit d’ajouter un fichier texte banner.txt dans le classpath ou de préciser sa location via le banner.location dans la configuration. Le charset d’encodage peut être spécifié si ce n’est pas de l’UTF-8. Il est également possible d’utiliser une image : banner.gif, banner.jpg ou banner.png qui est transformé en ASCII Art au lancement.

Nous pouvons utiliser ce site pour faire de l’ASCII Art : http://patorjk.com/software/taag

La propriété spring.main.banner-mode est utilisée pour déterminer si la bannière est affichée sur la console System.out, la log log, ou pas du tout off.

Événements d’applications

Spring notifie, via des événements, certaines choses, comme par exemple le rafraîchissement du contexte via l’événement ContextRefreshedEvent :

@Component  
public class MyListener {  
 @EventListener  
 public void handleContextRefresh(ContextRefreshedEvent event) {  
 ...  
 }  
} 

Ceci permet à la classe MyListener d’être averti lorsque le contexte a été actualisé et on peut l’utiliser pour exécuter du code arbitraire lorsque le contexte de l’application a complètement démarré. Les événements sont importants pour déterminer le readiness (l’application peut recevoir des requêtes) et le liveness (l’application est démarrée).

Une application Spring Boot met à disposition les événements suivants :

  • L’événement ApplicationStartingEvent est émis au début d’une exécution, mais avant tout traitement, à l’exception de l’enregistrement des écouteurs et des initialiseurs.

  • L’événement ApplicationEnvironmentPreparedEvent est envoyé lorsque l’environnement à utiliser dans le contexte est connu, mais avant la création du contexte.

  • L’événement...

La récupération des arguments de la ligne de commande

Il y a deux interfaces Spring Boot permettant d’exécuter du code juste avant que l’application finisse son démarrage via deux interfaces : CommandLineRunner et ApplicationRunner. Ces interfaces sont appelées juste avant la méthode run() une fois que SpringApplication a terminé. Ceci peut aussi faire partie de la phase de configuration de l’application.

1. CommandLineRunner

Cette interface permet d’obtenir les arguments de la ligne de commande sous forme d’un tableau.

@SpringBootApplication  
public class SpringBootWebApplication implements CommandLineRunner { 
 public static void main(String[] args) throws Exception {  
   SpringApplication.run(SpringBootWebApplication.class, args);  
 }  
 @Override  
 public void run(String... args) throws Exception {  
   logger.info("Application Started !!");  
 }  
} 

2. ApplicationRunner

Cette interface permet d’accéder aux arguments via l’interface ApplicationArguments qui expose plusieurs façons d’obtenir ces arguments :

  • getOptionNames() : retourne la liste des noms des arguments.

  • getOptionValues() : retourne la liste des valeurs des arguments.

  • getSourceArgs() : retourne la liste des valeurs des arguments.

@Slf4j  
public class SpringBootApplicationRunner...

L‘annotation EnableConfigurationProperties

L’annotation @ConfigurationProperties permet de définir une classe typée dans laquelle on peut injecter des données.

À partir de la base de la clé, Spring applique les propriétés sur les champs de la clé. L’annotation @EnableConfigurationProperties permet de l’activer. Cette annotation est de type @Import.

Cette annotation active la possibilité d’importer des définitions de Beans dans le Registrar juste après l’import des Beans Spring.

La configuration des logs

Spring Boot utilise le Commons Logging pour toutes les logs, mais il est possible de changer le comportement par défaut. Les configurations par défaut sont fournies pour Java Util Logging, Log4J2 et Logback. Dans chaque cas, les enregistreurs sont pré-configurés pour utiliser la sortie de la console avec la sortie de fichier facultative.

Par défaut, si vous utilisez les starters, Logback sera utilisé pour les logs. Le routage Logback approprié est également inclus pour garantir que les bibliothèques dépendantes qui utilisent Java Util Logging, Commons Logging, Log4J ou SLF4J fonctionnent correctement.

Nous avons à notre disposition les niveaux de logs classiques FATAL (sauf pour Logback), ERROR, WARN, INFO, DEBUG et TRACE.

1. Les logs en couleur

Si on ne spécifie rien, la log est monochrome, mais il est possible de mettre de la couleur dans les logs. Le système utilisé par défaut est Logback qui supporte les couleurs.

Pour ce faire, il faut positionner la variable de configuration : spring.output.ansi.enabled=always.

La première possibilité consiste à mettre un format pour la log dans le fichier de configuration de l’application :

Dans le fichier de configuration :

logging.pattern.console=%d{dd-MM-yyyy HH:mm:ss.SSS} 
%magenta([%thread]) %highlight(%-5level) %logger.%M - %msg%n 

Ici nous créons des logs pour les voir en couleur :

LOGGER.trace("Test des logs:trace");  
LOGGER.debug("Test des logs:debug");  
LOGGER.info("Test des logs:info");  
LOGGER.warn("Test des logs:warn");  
LOGGER.error("Test des logs:error"); 

Log affichée :

02-03-2018 12:42:27.545 [main] TRACE 
fr.eni.spring5.logs.Ex1Logs.run - Test des logs:trace  
02-03-2018 12:42:27.545 [main] DEBUG 
fr.eni.spring5.logs.Ex1Logs.run - Test des logs:debug  
02-03-2018 12:42:27.545 [main] INFO 
fr.eni.spring5.logs.Ex1Logs.run - Test des logs:info  
02-03-2018 12:42:27.545 [main] WARN 
fr.eni.spring5.logs.Ex1Logs.run - Test des logs:warn  
02-03-2018 12:42:27.545 [main] ERROR 
fr.eni.spring5.logs.Ex1Logs.run - Test des logs:error 

Nous avons alors :

  • pour les blocs [main] pour le thread en rose.

  • TRACE et DEBUG en noir.

  • INFO en bleu.

  • WARN en orange.

  • ERROR en rouge.

Une autre possibilité est d’utiliser...

L’auto-configuration pour Spring MVC

Spring propose une auto-configuration de Spring MVC via le starter spring-boot-starter-web.

Cela provoque la prise en compte de :

  • L’inclusion du bean ContentNegotiatingViewResolver et du bean BeanNameViewResolver.

  • Du support des ressources statiques, d’un index.html, d’un Favicon personnalisé et des WebJars.

  • De l’enregistrement automatique des beans Converter, GenericConverter, Formatter et MessageCodesResolver.

  • Du support des HttpMessageConverters et de l’utilisation automatique d’un bean ConfigurableWebBindingInitializer.

Il est possible de ne garder que les fonctionnalités Spring MVC en ajoutant les beans de configuration intercepteurs, formateurs, contrôleurs de vues en créant notre propre classe @Configuration de type WebMvcConfigurerAdapter, mais il ne faut alors pas utiliser l’annotation @EnableWebMvc. Il est possible de fournir une instance personnalisée de RequestMappingHandlerMapping, RequestMappingHandlerAdapter ou ExceptionHandlerExceptionResolver via la déclaration d’une instance de WebMvcRegistrationsAdapter. Nous pouvons aussi prendre le contrôle complet de Spring MVC en ajoutant notre propre classe de configuration (annotée par @Configuration) annotée avec @EnableWebMvc.

La gestion des sessions

Nous essayons d’être stateless car la gestion des sessions complique la mise en cluster des serveurs à cause du partage de session. Nous « émulons » alors la session via un cache partagé.

Dans certains cas, nous n’avons pas le choix, il faut gérer des sessions. Les sessions peuvent alors être gérées dans le projet Spring Session qui a deux versions en parallèle. Ce projet a pour but d’offrir une alternative aux sessions des conteneurs Tomcat, Jetty...

Le module Spring Session gère les sessions.

Il y a des différences entre les deux implémentations.

Version

Informations

HttpSession

WebSocket

WebSession

1.5

Spring 4.x

oui

oui

non

2.6

Spring 5.x

oui

oui

oui

Dans ce tableau, Spring 4 et 5 correspondent aux versions 1.5 et 2.6 de Spring Boot.

HttpSession (Spring) : remplace le HttpSession dans un conteneur (Tomcat) de façon neutre en ajoutant les fonctionnalités suivantes :

  • Sessions clustérisées.

  • Session de navigateurs multiples : plusieurs utilisateurs connectés dans une même instance de navigateur.

  • APIs RESTful : les identifiants de sessions dans les headers.

WebSocket : permet de garder la session HttpSession vivante quand nous recevons des messages WebSocket.

WebSession : permet le remplacement des WebSession d’une application conteneurisée Spring...

Le guide de migration de la version 1.5 à la version 2.x

Au niveau de la migration de Spring Boot 1.5 vers la version 2.x, la documentation Spring liste un certain nombre de points.

1. Fichiers de configuration

Certaines propriétés ont été changées entre la version 1.5 et la version 2.x. Un starter spécifique a été mis à disposition pour faciliter la migration. Il assure une relative rétro-compatibilité le temps de la migration.

<dependency>  
  <groupId>org.springframework.boot</groupId>  
  <artifactId>spring-boot-properties-migrator</artifactId>  
</dependency> 

2. Comportements différents

Les applications Spring Boot peuvent désormais fonctionner dans de nouveaux modes. C’est pourquoi, la propriété spring.main.web-environment est désormais obsolète et remplacée par spring.main.web-application-type qui offre plus de contrôle.

3. Démarrage

Il est possible de différer le démarrage du serveur web au démarrage de l’application en changeant la propriété spring.main.web-application-type=none ou d’utiliser le setWebApplicationType sur SpringApplication pour le faire par programmation.

4. Utilisation de ApplicationRunner ou CommandLineRunner

Dans la version 1.x, les beans ApplicationRunner et CommandLineRunner sont invoqués au démarrage du processus...

Description avancée de Spring Boot

Ce paragraphe décrit le lancement d’un programme Spring Boot. Il permet de démystifier une fois de plus la « magie » apparente du système qui est en fait le résultat d’un travail intéressant et consciencieux. Spring utilise pour son compte les mécanismes de Spring Boot qu’il met à notre disposition.

Les sources de Spring Boot sont visibles ici : https://github.com/spring-projects/spring-boot. Nous pouvons étudier le comportement de Spring Boot au démarrage à partir des sources. Une application Spring Boot se caractérise par deux éléments : l’annotation @SpringBootConfiguration et la méthode statique RUN au sein d’un programme Java standard :

@SpringBootApplication  
public class Application {  
public static void main(String[] args) {  
 SpringApplication.run(Application.class, args);  
 }  
} 

L’annotation @SpringBootApplication est une composition des annotations @SpringBootConfiguration, @EnableAutoConfiguration et @ComponentScan avec leurs attributs par défaut.

Comme nous l’avons vu, l’annotation @SpringBootConfiguration est un alias vers l’annotation @Configuration et l’annotation @EnableAutoConfiguration indique que nous avons de la configuration embarquée...

Le chargement du BootstrapContext

Spring Boot commence par initialiser le BootstrapContext qui est un mini contexte Spring temporaire épuré pour la phase d’initialisation. Le BootstrapContext a été introduit avec Spring Boot version 2.4 pour faciliter la mise en œuvre des modules Spring Cloud. Il permet au framework de préparer le contexte de l’application. Ce contexte se base sur deux interfaces : BootstrapRegistry qui gère les écritures dans le contexte et BootstrapContext qui gère la partie lecture.

BootstrapRegistry : enregistrement de la classe dans le contexte via la méthode register.

BootstrapContext : chargement de la classe dans le contexte via la méthode get(Class <T> type).

Ce contexte est plus simple car il ne permet d’associer qu’une seule classe à un type.

Exemple d’utilisation :

//Ecriture dans le contexte : 
bootstrapContext.register(MaClasse.class,  
InstanceSupplier.from(MaClasse::new).withScope(Scope.SINGLETON)) ; 

Lecture dans le contexte :

Un fois Spring démaré, Spring appelle le addCloseListener du bootstrap context pour enregistrer les beans dans le vrai contexte Spring de l’application.

Une fois le contexte chargé, Spring prépare le listener de démarrage pour gérer la partie événementielle.

Mise en place des listeners

Spring Boot utilise l’interface SpringApplicationRunListener qui a pour implémentation EventPublishingRunListener.

C’est ce listener qui va envoyer les événements durant la phase d’initialisation :

Evénement

Signification

starting

ApplicationStartingEvent

environmentPrepared

ApplicationEnvironmentPreparedEvent

contextPrepared

ApplicationContextInitilizedEvent

ContextLoaded

ApplicationPreparedEvent

started

ApplicationStartedEvent

running

ApplicationReadyEvent

failed

ApplicationFailedEvent

Nous avons déjà présenté certains de ces événements.

1. Le starting : ApplicationStartingEvent

Il est possible d’enregistrer des listeners comme nous l’avons vu dans le chapitre sur les listeners :

class MonListener implements ApplicationListener<ApplicationStartingEvent> { 
 void onApplicationEvent(ApplicationStartingEvent event {...}  
} 

Étant donné qu’à ce moment précis du démarrage Spring ne dispose pas encore du contexte normal de l’application, il va se baser sur le BootstrapContext que nous pouvons alimenter de trois façons :

  • Utiliser le chargement des factories via la mécanique du spring.factories en ajoutant une ligne au org.springframework.context.ApplicationListener.

  • Utiliser les méthodes SpringApplication.addListeners(...) et SpringApplicationBuilder.listeners(...).

  • Ajouter le listener dans le classpath au démarrage : -Dcontext.listener.classes=...

La propagation des événements se fait dans l’implémentation par défaut via la création et l’utilisation d’un initialMulticaster dans lequel Spring enregistre tous les listeners. Il y a ensuite publication et dispatch des événements pour tous les événements jusqu’à...

La configuration des logs

Nous avons trois événements :

Événement

Actions

ApplicationStartingEvent

Initalisation du système de logs (LoggingSystem)

ApplicationEnvironmentPreparedEvent

Choix des niveaux de logs

ApplicationPrteparedEvent

Enregistrement du logger dans le contexte

L’ApplicationStartingEvent configure la log par ordre de préférence pour logback, Log4j et le LogManager du JDK.

ApplicationEnvironmentPreparedEvent récupère les niveaux de log par package, comme par exemple logging.level.root=info.

À ce moment nous créons le vrai contexte Spring.

Création de l’ApplicationContext

Spring scanne tous les packages (avec ASM) et utilise les BeanProcessor.

La BeanFactoryPostProcessor utilise le ConfigurationClassPostProcessor pour identifier et gérer les Beans Spring @Configuration, @Component, @Repository@Service et @Controller.

Le BeanPostProcessor utilise l’AutowiredAnnotationBeanPostProcessor pour l’Autowire : @Autowired, @Value, les constructeurs, le CommonAnnotationBeanPostProcessor pour la JSR-250 : les @Resource, @PostConstruct, le PersistenceAnnotationBeanPostProcessor pour JPA et l’EventListenerMethodProcessor et le DefaultEventListenerFactory pour les @EventListener.

Préparation et rafraîchissement du contexte

Pour la phase de préparation, le contexte BootstrapContext est recopié dans le contexte normal et l’évenement contextPrepared est émis. Le BootstrapContext est ensuite clôturé, la définition du Bean principal (qui contient le main) est ajouté au contexte puis l’événement contextLoaded est émis.

Lors de la phase de refresh, le contexte Spring est initialisé, le conteneur web (Jetty, Tomcat…) est lancé sans autoriser les connexions.

Les stubs de propriétés sont remplacés et les beans (non lazy) sont alors créés. Sping signale alors au serveur embarqué qu’il peut accepter les connexions et l’événement ContextRefreshEvent est lancé.

À ce moment précis, le contexte Spring est chargé mais il reste la partie concernée par l’autoconfiguration (annotation @EnableAutoConfiguration).

L’EnableAutoConfigurtation

L’annotation EnableAutoConfigurtation est de type Import.

@Target(ElementType.TYPE) 
@Retention(RetentionPolicy.RUNTIME) 
@Documented 
@Inherited 
@AutoConfigurationPackage  
@Import(AutoConfigurationImportSelector.class) 
public @interface EnableAutoConfiguration { 
 
        /** 
        * Environment property that can be used to override 
when auto-configuration is 
        * enabled. 
        */ 
        String ENABLED_OVERRIDE_PROPERTY =  
"spring.boot.enableautoconfiguration"; 
 
        /** 
        * Exclude specific auto-configuration classes such that they will never be applied. 
        * @return the classes to exclude 
        */ 
        Class<?>[] exclude() default {}; 
 
        /** 
        * Exclude specific auto-configuration class names such that they will never be 
        * applied. 
        * @return the class names to exclude 
        * @since 1.3.0 
        */ 
        String[] excludeName() default {}; ...

Lancement des runners

Juste après l’émission de l’événement started, Spring lance les runners.

Les runners sont surtout utilisés pour les applications en ligne de commande. Les runners sont de deux types, que nous avons présentés : l’ApplicationRunner et le CommandLineRunner.

Une fois le code du run exécuté, Spring émet l’événement Running.

Ceci conclut le cycle de lancement de l’application Spring Boot.

Points clés

  • Spring Boot est utilisé pour les applications qui sont en production.

  • Spring Boot réduit considérablement le code à produire.

  • Spring Boot peut permettre de faire des composants auto-configurables.