Servlet



1. Introduction

Une servlet est une classe Java qui respecte la spécification JEE ; elle hérite de certaines classes et interfaces bien précises.
La spécification JEE définie les méthodes (noms des méthodes, types des paramètres, et types des valeurs retournées) qui seront invoquées dynamiquement par le conteneur de servlets pour répondre aux événements nécessaires à l’exécution de l’application web (exemple, traiter une requête http).

2. Cycle de vie des servlets

  1. Chargement de la classe servlet en mémoire
    Une classe servlet peut être chargée en mémoire :
    - au démarrage du conteneur de servlets,
    - au déploiement de l’application,
    - à la réception de la première requête sur la servlet,
    - ou à n'importe quel moment entre le démarrage du conteneur de servlets et la réception de la première requête sur la servlet ; le conteneur de servlets, en absence de configuration spéciale, lui seul décide quand !

    Après le chargement de la classe :
    - tous les champs statiques de la classe seront initialisés (exemple : static String myVar1 = "";)
    - tous les blocs de code statiques de la classe seront exécutés (exemple : static { /* doSomeThing */ }).

  2. Instanciation de la classe de la servlet
    Se produit juste après le chargement de la classe ou si le conteneur de servlets décide de créer une nouvelle instance de la servlet.

    Après l’instanciation de la classe :
    - tous les champs d’instance de la classe seront initialisés
    - tous les blocs de code d’instance de la classe seront exécutés.
    - le constructeur sans argument (si définit) sera aussi invoqué.

    Rappel : Si le constructeur sans argument n’est pas défini dans le code, alors il sera par défaut ajouté dans le bytecode de la classe à condition que le code ne déclare pas un constructeur avec des arguments.

  3. Invocation de la méthode init()
    Se produit juste après l’instanciation de la classe.
    Elle est appelée une et une seule fois pour une instance.

  4. Invocation de la méthode service()
    À la réception de chaque nouvelle requête sur la servlet.

  5. Invocation de la méthode destroy()
    Se produit quand le conteneur de servlets décide de ne plus utiliser l’instance de la servlet :
    Possiblement à l’arrêt du conteneur de servlets, à l’arrêt de l’application, ou à n'importe quel moment où le conteneur de servlets décide de détruire l’instance parce qu’elle est n’est plus appelée ou juste pour libérer temporairement de la mémoire.
package ca.habti.servlets.test1;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@SuppressWarnings("serial")
public class MyServlet1 extends HttpServlet {
    @Override
    public void init() throws ServletException {
        // TODO Auto-generated method stub
        super.init();
    }

    @Override
    public void service( HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException {
        // TODO Auto-generated method stub
    }

    @Override
    public void destroy() {
        // TODO Auto-generated method stub
        super.destroy();
    }
}

2.1) La méthode init()

Le conteneur de servlets doit appeler cette méthode une seule fois (et uniquement une seule fois) pour chaque instance créée de la servlet.
Typiquement vous utilisiez cette méthode pour écrire un code qui doit être exécuté une seule fois durant toute la vie de l’instance de la servlet.

Le conteneur de servlets doit exécuter la méthode init() sans erreurs pour autoriser les requêtes sur la servlet.
Il y a deux scenarios possibles à l’échec de l’exécution de cette méthode :
  1. Le temps d’exécution dépasse le temps maximal configuré dans le conteneur de servlets.

  2. La méthode renvoie une erreur ou une exception.
    Il y a deux types d’exceptions : ServletException et UnavailableException.
    L’exception UnavailableException ajoute la possibilité de préciser un temps d’inaccessibilité de la servlet.

2.2) La méthode service()

Cette méthode est appelée à chaque réception d’une requête sur la servlet.
Les requêtes multiples sur une servlet utilisent des threads distincts, potentiellement sur la même instance de la servlet.

La méthode service() est définie dans l’interface Servlet et accepte deux paramètres de type ServletRequest et ServletResponse.
Elle est implémentée dans la classe HttpServlet et accepte deux paramètres de type HttpServletRequest et HttpServletResponse.

En fonction de la méthode http de la requête, cette méthode appel dynamiquement la méthode appropriée doHTTP_METHOD_NAME (doGet, doPost, ...).
Voici un aperçu du code de la méthode service() de la classe HttpServlet :
package javax.servlet.http;

public abstract class HttpServlet extends GenericServlet implements Serializable {
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String method = req.getMethod();

        if(method.equals("GET")) {
            // doCallGetMethod
        } else if(method.equals("POST")) {
            // doCallPostMethod
        } else if(method.equals("HEAD")) {
            // doCallHeadMethod
        } else if(method.equals("OPTIONS")) {
            // doCallOptionsMethod
        } else if(method.equals("TRACE")) {
            // doCallTraceMethod
        } else if(method.equals("PUT")) {
            // doCallPutMethod
        } else if(method.equals("DELETE")) {
            // doCallDeleteMethod
        } else {
            // doThrowError
        }
    }
}

2.3) La méthode destroy()

Quand le conteneur de servlets décide de détruire une instance de la servlet, il appel la méthode destroy().
Elle peut être utilisée pour écrire du code qui libère les ressources qui ont été allouées dans la méthode init().

La méthode est appelée quand le conteneur de servlets décide de ne plus utiliser l’instance de la servlet, mais avant, il faut :
- que tous les threads qui ont été créés pour répondre aux requêtes http soient terminés (ce qui veut dire que la méthode service(), de l’instance qui sera détruite, a complétée son exécution pour tous les threads) ;
- ou que le temps d’exécution maximal, configuré dans le conteneur de la servlet, ait été dépassé.

Il faut noter aussi que, pour une instance donnée, cette méthode ne sera jamais appelée si la méthode init() a échouée (suite à une erreur ou une exception).

2.4) Exemple

package ca.habti.servlets.test1;

import java.io.IOException;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@SuppressWarnings("serial")
public class MyServlet2 extends HttpServlet {
    @Override
    public void init(ServletConfig config) throws ServletException {
        System.out.println("MyServlet2 : init(ServletConfig) : Start");
        super.init(config);
        System.out.println("MyServlet2 : init(ServletConfig) : End");
    }

    @Override
    public void init() throws ServletException {
        System.out.println("MyServlet2 : init() : Start");
        super.init();
        System.out.println("MyServlet2 : init() : End");
    }

    @Override
    public void service(ServletRequest arg0, ServletResponse arg1) throws ServletException, IOException {
        System.out.println("MyServlet2 : service(ServletRequest, ServletResponse) : Start");
        super.service(arg0, arg1);
        System.out.println("MyServlet2 : service(ServletRequest, ServletResponse) : End");
    }

    @Override
    public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("MyServlet2 : service(HttpServletRequest, HttpServletResponse)");
    }
}
Dans la console DOS, on obtient le résultat suivant lorsque la servlet est appelée :
MyServlet2 : init(ServletConfig) : Start
    MyServlet2 : init() : Start
    MyServlet2 : init() : End
MyServlet2 : init(ServletConfig) : End

MyServlet2 : service(ServletRequest, ServletResponse) : Start
    MyServlet2 : service(HttpServletRequest, HttpServletResponse)
MyServlet2 : service(ServletRequest, ServletResponse) : End
Vous remarquiez que les méthodes définies dans les superclasses sont exécutés les premières.

3. Paramètres d’initialisation

Il est possible d’associer des paramètres d’initialisation pour la servlet, il s’agit des paramètres renseignés dans le fichier descripteur de l’application web (web.xml) par les éléments <param-name>, et <param-value> de l’élément <init-param>.
Ces paramètres sont accessibles en lecture seulement en utilisant les méthodes :
Exemple :