Gestion des Événements du Cycle de Vie et des Attributs avec les Listeners Java EE

Dans le développement d'applications web Java, les "listeners" (écouteurs) jouent un rôle fondamental pour intercepter et réagir à divers événements se produisant au sein de l'environneemnt du serveur web. Ces événements peuvent concerner le cycle de vie des objets fondamentaux comme les requêtes, les sessions et le contexte d'application, ainsi que les modifications de leurs attributs. En implémentant les interfaces d'écouteur appropriées, les développeurs peuvent exécuter une logique personnalisée à des moments spécifiques, permettant ainsi la gestion de tâches d'initialisation, de nettoyage, de journalisation ou de surveillance.

Le principe des écouteurs repose sur le modèle de conception "Observateur". Lorsqu'un événement est déclenché (par exemple, la création d'une nouvelle session), le conteneur web informe tous les écouteurs enregistrés pour ce type d'événement, qui peuvent alors exécuter les méthodes implémentées pour y répondre. Cela offre une approche puissante et découplée pour gérer les comportements réactifs dans une application web.

Catégories d'Interfaces d'Écouteurs

Les interfaces d'écouteurs sont regroupées en plusieurs catégories selon l'objet qu'elles surveillent et le type d'événement.

1. Écouteurs de Cycle de Vie des Objets Web

Ces écouteurs sont déclenchés lors de la création ou de la destruction des objets principaux du conteneur web :

  • ServletRequestListener : Surveille la création et la destruction des objets ServletRequest.
  • HttpSessionListener : Surveille la création et la destruction des objets HttpSession.
  • ServletContextListener : Surveille le démarrage et l'arrêt du contexte d'application web (objet ServletContext).

2. Écouteurs de Modifications d'Attributs

Ces écouteurs sont déclenchés lorsqu'un attribut est ajouté, modifié ou supprimé dans un objet donné :

  • ServletRequestAttributeListener : Surveille les changements d'attributs dans un ServletRequest.
  • HttpSessionAttributeListener : Surveille les changements d'attributs dans une HttpSession.
  • ServletContextAttributeListener : Surveille les changements d'attributs dans un ServletContext.

3. Écouteurs Spécifiques à la Session

Ces écouteurs gèrent des événements plus granulaires liés aux sessions :

  • HttpSessionBindingListener : Permet à un objet de savoir quand il est lié ou délié à une session. L'objet lui-même implémente cette interface.
  • HttpSessionActivationListener : Déclenché lorsqu'un objet de session est activé ou désactivé (sérialisé/désérialisé) lors de la migration de session.

Mise en Œuvre et Configuration des Écouteurs

Pour utiliser un écouteur, deux étapes principales sont nécessaires :

  1. Création de la Classe d'Écouteur : Écrivez une classe Java ordinaire qui implémente l'interface d'écouteur souhaitée et surcharge ses méthodes d'événement. C'est dans ces méthodes que votre logique personnalisée sera exécutée.
  2. Déclaration dans le Fichier de Déploiement : Enregistrez votre écouteur dans le fichier web.xml de votre application web. Pour les versions plus modernes de la spécification Servlet (3.0+), les annotations (par exemple, @WebListener) peuvent également être utilisées.

Exemples de Classes d'Écouteurs

Voici des exemples de classes implémentant les écouteurs de cycle de vie les plus courants. Les messages de journalisation sont utilisés pour illustrer quand chaque méthode est appelée.

Écouteur de Contexte d'Application (ServletContextListener)

Cet écouteur est utile pour exécuter des actions une seule fois au démarrage et à l'arrêt de l'application.

package fr.devtech.web.listeners;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import java.time.LocalDateTime;

public class GestionnaireContexte implements ServletContextListener {

   @Override
   public void contextInitialized(ServletContextEvent event) {
       event.getServletContext().setAttribute("dateDemarrageApplication", LocalDateTime.now());
       System.out.println("INFO: L'application web a démarré à " + LocalDateTime.now());
       System.out.println("INFO: Contexte de servlet initialisé. Nom : " + event.getServletContext().getServletContextName());
   }

   @Override
   public void contextDestroyed(ServletContextEvent event) {
       LocalDateTime demarrage = (LocalDateTime) event.getServletContext().getAttribute("dateDemarrageApplication");
       if (demarrage != null) {
           long uptimeSeconds = java.time.Duration.between(demarrage, LocalDateTime.now()).getSeconds();
           System.out.println("INFO: L'application web s'est arrêtée après " + uptimeSeconds + " secondes de fonctionnement.");
       } else {
           System.out.println("INFO: L'application web s'est arrêtée à " + LocalDateTime.now());
       }
       System.out.println("INFO: Contexte de servlet détruit.");
   }
}

Écouteur de Session (HttpSessionListener)

Cet écouteur permet de suivre la création et la destruction des sessions utilisateur, par exemple pour compter les utilisateurs actifs ou gérer les ressources liées à la session.

package fr.devtech.web.listeners;

import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import java.time.LocalDateTime;
import java.util.concurrent.atomic.AtomicInteger;

public class GestionnaireSession implements HttpSessionListener {

   private static final AtomicInteger sessionsActives = new AtomicInteger(0);

   @Override
   public void sessionCreated(HttpSessionEvent event) {
       sessionsActives.incrementAndGet();
       System.out.println("INFO: Nouvelle session créée (ID: " + event.getSession().getId() + ") à " + LocalDateTime.now() + ". Sessions actives: " + sessionsActives.get());
       event.getSession().setAttribute("creationTime", LocalDateTime.now());
   }

   @Override
   public void sessionDestroyed(HttpSessionEvent event) {
       sessionsActives.decrementAndGet();
       System.out.println("INFO: Session détruite (ID: " + event.getSession().getId() + ") à " + LocalDateTime.now() + ". Sessions actives: " + sessionsActives.get());
       LocalDateTime creationTime = (LocalDateTime) event.getSession().getAttribute("creationTime");
       if (creationTime != null) {
           long durationSeconds = java.time.Duration.between(creationTime, LocalDateTime.now()).getSeconds();
           System.out.println("INFO: La session a duré " + durationSeconds + " secondes.");
       }
   }
}

Écouteur de Requête (ServletRequestListener)

Cet écouteur permet d'effectuer des opérations au début et à la fin de chaque requête web, comme la journalisation des temps de réponse ou l'initialisation de contextes de threads.

package fr.devtech.web.listeners;

import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import java.time.LocalDateTime;

public class GestionnaireRequete implements ServletRequestListener {

   @Override
   public void requestInitialized(ServletRequestEvent event) {
       // Pour les versions récentes de Servlet API (6.0+), on pourrait utiliser event.getServletRequest().getRequestId();
       String identifiantRequete = String.valueOf(event.getServletRequest().hashCode());
       System.out.println("DEBUG: Requête [" + identifiantRequete + "] initialisée à " + LocalDateTime.now());
       event.getServletRequest().setAttribute("heureDebutTraitement", LocalDateTime.now());
   }

   @Override
   public void requestDestroyed(ServletRequestEvent event) {
       String identifiantRequete = String.valueOf(event.getServletRequest().hashCode());
       LocalDateTime heureDebut = (LocalDateTime) event.getServletRequest().getAttribute("heureDebutTraitement");
       if (heureDebut != null) {
           long dureeMs = java.time.Duration.between(heureDebut, LocalDateTime.now()).toMillis();
           System.out.println("DEBUG: Requête [" + identifiantRequete + "] détruite après " + dureeMs + " ms de traitement.");
       } else {
           System.out.println("DEBUG: Requête [" + identifiantRequete + "] détruite.");
       }
   }
}

Configuration dans web.xml

Une fois les classes d'écouteurs implémentées, elles doivent être déclarées dans le descripteur de dépoliement de l'application web, web.xml, pour que le conteneur web puisse les instancier et les enregistrer.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                            http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
        version="4.0">

   <!-- Déclaration des écouteurs personnalisés -->

   <listener>
       <listener-class>fr.devtech.web.listeners.GestionnaireContexte</listener-class>
   </listener>
   <listener>
       <listener-class>fr.devtech.web.listeners.GestionnaireSession</listener-class>
   </listener>
   <listener>
       <listener-class>fr.devtech.web.listeners.GestionnaireRequete</listener-class>
   </listener>

</web-app>

Page JSP pour Déclencher les Événements

Pour observer le comportement de ces écouteurs, une simple page JSP peut déclencher des requêtes et manipuler des sessions, ce qui sera reflété dans les journaux du serveur.

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<html>
<head>
   <meta charset="UTF-8">
   <title>Page de Test des Écouteurs</title>
</head>
<body>
   <h1>Bienvenue sur la page de test des écouteurs !</h1>
   <p>Cette page est conçue pour déclencher divers événements observés par les écouteurs de l'application.</p>
   <%
       // Définir un attribut dans l'objet request
       request.setAttribute("utilisateurCourant", "Alice Durand");
       out.println("<p>Attribut 'utilisateurCourant' défini dans la requête.</p>");

       // Définir un attribut dans la session (peut être utile pour des écouteurs d'attributs de session)
       session.setAttribute("languePreferee", "Français");
       out.println("<p>Attribut 'languePreferee' défini dans la session.</p>");

       // Invalider explicitement la session pour déclencher l'événement de destruction
       // Cela forcera l'appel à la méthode sessionDestroyed() de l'écouteur de session.
       session.invalidate();
       out.println("<p>La session actuelle a été invalidée. Un nouvel accès créera une nouvelle session.</p>");
   %>
   <p>Vérifiez les journaux de votre serveur (console) pour voir les messages générés par les écouteurs.</p>
</body>
</html>

Étiquettes: Java EE Servlet JSP Web Listener HttpSessionListener

Publié le 4 août à 04h02