Point d'entrée : DispatcherServlet
Lorsqu'une requête HTTP parvient à l'application (par exemple GET /api/produits/42), le conteneur web (Tomcat, Jetty, etc.) la dirige vers le DispatcherServlet. Ce dernier hérite de HttpServlet et effectue tout son travail dans la méthode doDispatch(), appelée par doService().
Le rôle de doDispatch() consiste à orchestrer le pipeline complet : localiser le bon gestionnaire, l'exécuter, puis produire la réponse finale. Le DispatcherServlet ne contient aucune logique métier — il agit comme un chef d'orchestre qui coordonne plusieurs composants qu'il maintient sous forme de listes internes.
Localisation du gestionnaire : HandlerMapping
Une fois la requête reçue, le DispatcherServlet doit déterminer quel bloc de code doit la traiter. C'est la mission du HandlerMapping.
Au démarrage de l'application, le conteneur Spring scanne tous les beans et repère les méthodes annotées avec @RequestMapping ou ses dérivés (@GetMapping, @PostMapping, etc.). L'implémentation principale RequestMappingHandlerMapping construit alors une table de correspondance entre les motifs d'URL/méthodes HTTP et les objets HandlerMethod, puis la conserve en mémoire.
@RestController
@RequestMapping("/api/produits")
public class CatalogueController {
private final ProduitService produitService;
public CatalogueController(ProduitService produitService) {
this.produitService = produitService;
}
@GetMapping("/{reference}")
public ResponseEntity<ProduitDTO> recupererProduit(@PathVariable String reference) {
ProduitDTO produit = produitService.trouverParReference(reference);
return ResponseEntity.ok(produit);
}
}
Quand une requête arrive, le DispatcherServlet parcourt les HandlerMapping enregistrés. Dès qu'un d'eux identifie une correspondance, il ne renvoie pas uniquement le HandlerMethod : il retourne un HandlerExecutionChain, un objet qui enveloppe à la fois le gestionnaire cible et la liste des HandlerInterceptor applicables. Cette encapsulation permet d'exécuter les intercepteurs avant et après l'appel de la méthode métier.
Préparation de l'exécution : HandlerAdapter
Le DispatcherServlet sait désormais quelle méthode invoquer, mais reste confronté à un problème : comment appeler de façon générique une méthode Java dont la signature est arbitraire ? Les paramètres peuvent inclure @PathVariable, @RequestBody, @RequestParam, et le type de retour peut varier (String, objet, ResponseEntity, etc.).
Spring résout cette difficulté via le pattern Adapter avec l'interface HandlerAdapter. Le DispatcherServlet interroge chaque HandlerAdapter enregistré pour savoir s'il supporte le type de handler trouvé. L'implémentation RequestMappingHandlerAdapter prend en charge les HandlerMethod.
RequestMappingHandlerAdapter est sans doute le composant le plus sophistiqué de Spring MVC. Son fonctionnement se décompose en deux phases :
- Résolution des paramètres : il examine la signature de la méthode cible et, pour chaque paramètre, sollicite un
HandlerMethodArgumentResolveradapté. Par exemple, un paramètre annoté@PathVariabledéclenchePathVariableMethodArgumentResolver, qui extrait la valeur depuis l'URL, effectue la conversion de type, puis fournit l'argument prêt à l'emploi. Chaque annotation dispose de son propre résolveur. - Invocation par réflexion : une fois tous les paramètres assemblés, la méthode est invoquée via l'API Reflection de Java.
Exécution et résultat : ModelAndView
Après l'appel réflexif de la méthode du contrôleur, le HandlerAdapter récupère la valeur retournée et l'enveloppe dans un objet ModelAndView, qui combine :
- Model : un
Mapcontenant les données métier à transmettre à la vue. - View : soit un nom de vue logique (une simple chaîne), soit un objet
Viewconcret.
En interne, le HandlerAdapter s'appuie sur une collection de HandlerMethodReturnValueHandler pour traiter le retour selon sa nature. Un String est interprété comme un nom de vue logique. Si la méthode ou la classe porte l'annotation @ResponseBody (ou @RestController), le RequestResponseBodyMethodProcessor entre en jeu : il sérialise directement l'objet de retour via un HttpMessageConverter (par exemple Jackson pour produire du JSON) et l'écrit dans le corps de la réponse. Dans ce cas, aucune vue n'est résolue — l'étape suivante est court-circuitée.
Rendu : ViewResolver et View
Lorsque le DispatcherServlet reçoit un ModelAndView contenant un nom de vue logique comme "detail_produit", il doit transformer cette chaîne en une réponse concrète (HTML, etc.). Cette responsabilité incombe au ViewResolver.
Le DispatcherServlet itère sur les ViewResolver enregistrés. Par exemple, un InternalResourceViewResolver configuré avec le préfixe /WEB-INF/vues/ et le suffixe .jsp transformera "detail_produit" en chemin physique /WEB-INF/vues/detail_produit.jsp, puis instanciera un objet JstlView. Avec Thymeleaf, le ThymeleafViewResolver produira un ThymeleafView.
L'objet View obtenu expose une méthode render() qui fusionne les données du Model avec le template pour générer le contenu final. Le résultat est écrit dans le flux de sortie de la HttpServletResponse et renvoyé au navigateur. Le cycle requête-réponse s'achève ici.
Vue d'ensemble du flux
Requête HTTP
│
▼
DispatcherServlet
│
├─► (1) HandlerMapping ──► HandlerExecutionChain
│ (HandlerMethod + Interceptors)
│ │
├─► (2) HandlerAdapter ── supporte ce handler ?
│ │
│ ├─ (3) Résolution des arguments
│ ├─ (4) Invocation du Controller
│ └─ (5) Construction du ModelAndView
│ │
├─► (6) ViewResolver ──► View concrète
│
└─► (7) View.render() ──► Réponse HTTP
Spring Boot et l'auto-configuration de Spring MVC
En pratique, lorsque vous développez avec Spring Boot, vous ne configurez jamais manuellement ces composants. C'est l'auto-configuration qui s'en charge.
Spring Boot et Spring MVC entretiennent une relation de complémentarité : Spring MVC définit l'architecture et les contrats (DispatcherServlet, HandlerMapping, HandlerAdapter, etc.), tandis que Spring Boot assure l'assemblage et la simplification via la classe WebMvcAutoConfiguration.
Avec la dépendance spring-boot-starter-web, plusieurs mécanismes se mettent en place automatiquement :
- Suppression de web.xml : Spring Boot embarque un serveur web (Tomcat par défaut) et enregistre le
DispatcherServletde manière programmatique via l'API Servlet 3.0+ (ServletContainerInitializer), de façon totalement transparente. - Instanciation des composants clés :
WebMvcAutoConfigurationcrée et configure les beans essentiels —RequestMappingHandlerMapping,RequestMappingHandlerAdapter(avec son arsenal de résolveurs d'arguments, de gestionnaires de retour et de convertisseurs commeMappingJackson2HttpMessageConverter), plusieursViewResolver(dontContentNegotiatingViewResolver), ainsi que desHandlerExceptionResolverpour la gestion uniforme des erreurs. - Convention sur configuration : les ressources statiques placées sous
classpath:/static/ouclasspath:/public/sont automatiquement servies. Un fichierindex.htmlà la racine sert de page d'accueil. Toute personnalisation peut s'effectuer via les propriétésspring.mvc.*etserver.*dansapplication.propertiesouapplication.yml, sans nécessiter de classe de configuration Java explicite.
En résumé, Spring MVC spécifie ce qu'il faut faire et comment (les composants et leur séquence d'invocation), alors que Spring Boot détermine comment les assembler et comment simplifier leur configuration. Vous n'avez qu'à annoter vos contrôleurs avec @RestController et à implémenter votre logique métier — toute la machinerie Spring MVC est déjà câblée et opérationnelle en arrière-plan.