Ciclo de Vida y Procesamiento de Peticiones en Spring MVC

Flujo General de una Petición HTTP

El ciclo de vida de una solicitud en una aplicación Spring MVC sigue una secuencia estructurada que involucra al contenedor de servlets y al framework:

  1. El cliente emite una petición HTTP, por ejemplo: http://localhost:8080/app/api/users.action.
  2. El contenedor de servlets (como Tomcat) recibe la solicitud. Basándose en el url-pattern definido en web.xml, sabe que las peticiones con extensión *.action deben ser delegadas al DispatcherServlet.
  3. El DispatcherServlet actúa como controlador frontal. Consultando su contexto de aplicación (configurado en spring-mvc.xml), identifica que la ruta /api/users mapea al método listUsers() de un controlador específico.
  4. El DispatcherServlet despacha la ejecución hacia el método listUsers() del UserController.
  5. El framework invoca el método del controlador, el cual retorna un objeto ModelAndView. Finalmente, este resultado se resuelve y se redirige o reenvía a la vista correspondiente, como userList.jsp.

Análisis del Código Fuente y Ciclo de Vida del Servlet

Para comprender cómo Spring MVC inicializa y procesa las peticiones a bajo nivel, es necesario examinra el ciclo de vida del DispatcherServlet.

Inicialización del Contenedor

Cuando el servidor de aplicaciones arranca, el DispatcherServlet se instancia gracias a la directiva <load-on-startup>. Al heredar de HttpServlet, su método init() es envocado para preparar el contexto de Spring.

// Inicialización del contexto de Spring dentro del DispatcherServlet
@Override
public void init(ServletConfig config) throws ServletException {
    super.init(config);
    
    // Carga el archivo de configuración XML para crear el contexto de la aplicación
    WebApplicationContext mvcContext = new ClassPathXmlApplicationContext("spring-mvc.xml");
    
    // Almacena el contexto en el ServletContext para que esté disponible globalmente
    getServletContext().setAttribute("MVC_CONTEXT_ATTRIBUTE", mvcContext);
}

El propósito de esta inicialización es instanciar las clases anotadas con @Controller. Por ejemplo, se crea una instancia de UserController y se registra en el contenedor de IoC, funcionando internamente como un mapa: beanFactory.put("userController", userControllerInstance).

Procesamiento de la Solicitud

Cuando llega una petición, el contenedor invoca el método service() del servlet, que a su vez llama a doGet() o doPost(), los cuales delegan la lógica a doService(). El núcleo de Spring MVC reside en el método doDispatch():

// Flujo interno de despacho de peticiones
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    // 1. Determina el controlador adecuado para la petición actual
    // 2. Invoca el método handler (ej. UserController.listUsers())
    // 3. Maneja el ModelAndView resultante y resuelve la vista
}

El método doDispatch() es el punto central donde todas las peticiones HTTP son orquestadas, manejando el mapeo de URLs, la ejecución de interceptores y la invocación de los controladores.

Configuración de Escaneo de Anotaciones y Recursos Estáticos

En el archivo de configuración spring-mvc-servlet.xml, es fundamental habilitar el escaneo de componentes y el soporte para anotaciones.

<!-- Habilita el escaneo automático de componentes en el paquete especificado -->
<context:component-scan base-package="com.example.web.controllers"/>

<!-- Permite que el servlet por defecto del contenedor maneje recursos estáticos (CSS, JS, imágenes) -->
<mvc:default-servlet-handler/>

<!-- Activa el soporte para anotaciones de Spring MVC como @RequestMapping, @ResponseBody, etc. -->
<mvc:annotation-driven />

La etiqueta <mvc:annotation-driven /> es crucial. Registra automáticamente los mapeadores de handlers y los adaptadores necesarios para procesar las anotaciones. Sin esta configuración, las peticiones dinámicas no serían enrutadas a los controladores y caerían en el manejador de recursos estáticos por defecto.

Nota: Al utilizar <context:component-scan>, no es necesario incluir <context:annotation-config>, ya que el escaneo de componentes lo incluye implícitamente.

Resolución de Vistas con ViewResolver

El ViewResolver se encarga de traducir el nombre lógico de la vista retornado por el controlador en una ruta física real. La fórmula que utiliza es: prefijo + nombreVista + sufijo.

<!-- Configuración del resolutor de vistas para JSP -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <!-- Directorio base donde se almacenan las vistas -->
    <property name="prefix" value="/WEB-INF/pages/"/>
    <!-- Extensión de los archivos de vista -->
    <property name="suffix" value=".jsp"/>
</bean>

Con esta configuración, si un controlador retorna el nombre lógico "userList", el InternalResourceViewResolver lo transformará en la ruta física /WEB-INF/pages/userList.jsp.

Configuración Integral del Servlet

A continuación, se muestra la estructura base y consolidada para el archivo spring-mvc-servlet.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd
           http://www.springframework.org/schema/mvc
           http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- Escaneo de controladores -->
    <context:component-scan base-package="com.example.web.controllers"/>
    
    <!-- Manejo de recursos estáticos -->
    <mvc:default-servlet-handler />
    
    <!-- Soporte para anotaciones MVC -->
    <mvc:annotation-driven />

    <!-- Resolutor de vistas JSP -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

</beans>

Etiquetas: spring-mvc dispatcher-servlet view-resolver java-web ioc-container

Publicado el 7-5 05:44