Spring dans l'architecture MVC2 : DispatcherServlet

Distribution des tâches avec un servlet central

Ce site ne sera plus alimenté de contenu après août 2014. Tous les nouveaux articles seront redigés pour www.waitingforcode.com

Le point central de l'architecture web MVC sous Spring est DispatcherServlet. Il s'agit d'une sorte de distributeur des tâches. Chaque nouvelle requête HTTP est captée par DispatcherServlet. Ensuite, en analysant les propriétés de la requête (en-tête, URI), il décide quel contrôleur doit se charger de retourner une réponse. DispatcherServlet est un bon exemple d'implémentation d'un dessign pattern appelé front controller.

Qu'est-ce que c'est front controller design pattern ?

Ce design pattern est la réponse à la problématique de gestion centralisée des requêtes. Il consiste à créer un seul point d'entrée pour toutes les requêtes. Contrairement à plusieurs points d'accès, cela facilite la centralisation du code car tous les services, la gestion des vues et de navigation sont gérés par un seul contrôleur.

Front controller design pattern utilise donc un contrôleur en tant que point d'entrée initial pour chaque requête. Ce contrôleur gère la requête, les vues, les erreurs ainsi qu'invoque de divers services (par exemple authorization et authentification pour la sécurité).

Cet unique point d'entrée permet de réduire la quantité du code dupliqué. Il aide donc à maintenir l'application plus facilement. Néanmoins, il ne limite pas le nombre des contrôleurs disponibles dans le système à un seul.

Le design pattern en question evoque également la notion du dispatcher. Il peut être encapsulé dans le contrôleur principal aussi bien qu'être un élément séparé dans l'architecture. Il est l'étape intermédiaire entre le contrôleur principal et la vue.

DispatcherServlet dans Spring

On peut déterminer plusieurs dispatchers pour des patterns différents. Cependant, dans notre application d'exemple on va se limiter à un seul. Il s'agit d'une servlet nommé mainAppServlet qui va traiter toutes les requêtes (pattern appliqué est "/"). Voici comment se présente notre fichier web.xml :

afficher le code

Quelques éléments supplémentaires sont présents dans ce fichier. Tout d'abord, le <param-name /> contextConfigLocation. Il contient la liste des fichiers qui seront chargés et utilisés par l'application.

Concernant un listener, ContextLoaderListener, il a deux rôles :
- attacher le cycle de vie de l'ApplicationContext au cycle de vie du ServletContext
- automatiser la création de l'ApplicationContext

Pour accomplir ces deux tâches, il se base sur la liste des fichiers spécifiés dans le paramètre contextConfigLocation. Si ce paramètre est absent, le listener cherche le fichier de configuration par défaut, placé dans /WEB-INF/applicationContext.xml.

Et finalement, le DispatcherServlet qui charge également un fichier de configuration défini dans <contextConfigLocation />. Pourquoi il faut avoir ces deux endroits de configuration ? Le premier endroit, celui utiliser par ContextLoaderListener, contient une liste des éléments généraux (données de connexion à la base de données, définition des services, sécurité). Le fichier de configuration du DispatcherServlet contient uniquement les informations liées à l'application web (contrôleurs, view resolvers, mapping handlers). Ce fichier peut lire les fichiers définis dans le paramètre général contextConfigLocation. Par contre, le paramètre général contextConfigLocation ne peut pas lire le fichier de configuration propre à DispatcherServlet.

Tout à la fin on précise que DispatcherServlet doit s'appliquer à toutes les requêtes.

Flux d'exécution du DispatcherServlet

Le traitement de chaque requête par DispatcherServlet se fait de manière suivante :

  1. Il cherche WebApplicationContext et l'attache à la requête en tant qu'un attribut. Grâce à cela, contrôleur et d'autres éléments peuvent l'utiliser
  2. LocaleResolver est ensuite attaché à la requête. Grâce à cela, on peut gérer les éléments liés à la traduction de notre application (partie i18n dans Spring), comme les vues ou les informations textuels.
  3. ThemeResolver est attaché à la requête pour déterminer quel thème doit être utilise par les vues.
  4. Si MultipartResolver est spécifié, la requête est alors analysé sous angle de présence des fichiers. Si les fichiers sont trouvés, la requête est envoyée à MultipartHttpServletRequest pour le traitement.
  5. On recherche un handler. S'il est trouvé, on exécute la chaîne lui associée. Cette chaîne se compose du preprocessors, postprocessors et contrôleurs. Elle prépare le modèle de vue ou affiche la vue.
  6. Si le modèle de vue est retourné, la vue est affichée. Sinon, la vue n'est pas affichée, peut-être parce que la requête était déjà réalisée.

Pendant ce processus de traitement, HandlerExceptionResolver peut être appelé à chaque moment où une exception est lancée. Grâce à cela, on peut appliquer le comportement spécifique à de différentes exceptions.

Du DispatcherServlet aux contrôleurs

Les contrôleurs interprètent la demande de l'utilisateur et la transforment en un modèle de vue qui est ensuite affiché sur l'écran.

Dans notre application on utilisera les annotations pour marquer une classe en tant que contrôleur. Plus de détails à ce sujet se trouvent dans la partie contrôleurs dans une application web Spring.

Une question ? Une remarque ?

*

*

Moi

Développeur d'applications Internet et journaliste passionné par l'adjectif français. Un aigle polonais orienté vers la progression, volant très haut et écoutant du zouk après les matches du foot français.

Vous appréciez mon travail ?

Pour contribuer au développement de ce site, ou pour remercier pour des articles rédigés, vous pouvez faire un don.

Un conseil MySQL

Vous voulez pouvoir détecter quelles requêtes posent le problème de performance sans vouloir écrire un logger dans un langage côté serveur ?

Tout d'abord il faut activer le logging des requêtes lentes (log_slow_queries dans votre fichier de configuration du MySQL).

Dans un deuxième temps on doit préciser après combien de temps un requête devient lente. Pour faire cela, on va utiliser long_query_time (aussi dans le fichier de configuration du MySQL). En secondes, il précise le temps maximal de l'exécution d'une requête.

Pour en savoir plus, vous pouvez consulter la documentation MySQL sur log_slow_queries.