Interceptor en Java: Mecanismos de Implementación y Ejemplo Práctico con Spring

El interceptor en Java es un objeto que intercepta dinámicamente las invocaciones a acciones, proporcionando un mecanismo para ejecutar código antes o después de una acción, o incluso bloquear su ejecución. En programación orientada a aspectos (AOP), los interceptores se usan para interceptar métodos o campos y añadir operaciones adicionales. En el contexto de Spring, los interceptores son fundamentales para el manejo de solicitudes web.

Principio de Funcionamiento

Los interceptores se basan en proxies dinámicos, típicamente implementados mediante la reflexión de Java. En frameworks como Struts2, cuando una solicitud llega, el sistema instancia los interceptores configurados y los organiza en una lista. Estos interceptores se ejecutan en secuencia, permitiendo la intercepción en un orden definido. Spring encaspula este concepto, ofreciendo una integración más robusta con aplicaciones basadas en web.

Pasos para Crear un Interceptor Personalizado

  1. Implementar la interfaz HandlerInterceptor o extender la clase abstracta HandlerInterceptorAdapter de Spring.
  2. Registrar el interceptor en el archivo de configuración de Spring MVC.
  3. Asignar el interceptor a las acciones deseadas, ya sea de forma explícita o como interceptor predeterminado para todas las acciones.

Diferencias entre Filtros e Interceptores

Los filtros operan a nivel de solicitudes web y se ejecutan una vez durante la inicialización del contenedor Servlet. En cambio, los interceptores se aplican a invocaciones de métodos, pueden acceder al contexto de la acción y al stack de valores, y se ejecutan múltiples veces durante el ciclo de vida de una acción. Los filtros dependen del contenedor Servlet, mientras que los interceptores se basan en la reflexión de Java y son independientes.

Interceptores en Spring

Spring proporciona la clase abstracta HandlerInterceptorAdapter para simplificar la creación de interceptores. A continuación, se muestra un ejemplo base de esta clase con comentarios en español y nombres de variables modificados para claridad.


package org.springframework.web.servlet.handler;  
import javax.servlet.http.HttpServletRequest;  
import javax.servlet.http.HttpServletResponse;  
import org.springframework.web.servlet.HandlerInterceptor;  
import org.springframework.web.servlet.ModelAndView;  
public abstract class BaseInterceptor implements HandlerInterceptor {  
    // Se invoca antes de que el procesador de negocios maneje la solicitud  
    public boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object handler) throws Exception {  
        return true;  
    }  
    // Se ejecuta después de que el procesador maneje la solicitud pero antes de generar la vista  
    public void postHandle(HttpServletRequest req, HttpServletResponse resp, Object handler, ModelAndView modelAndView) throws Exception {  
    }  
    // Se llama después de que el DispatcherServlet haya procesado completamente la solicitud, útil para limpiar recursos  
    public void afterCompletion(HttpServletRequest req, HttpServletResponse resp, Object handler, Exception ex) throws Exception {  
    }  
} 

Spring también incluye interceptores predefinidos, como uno para autorización basada en roles. Se modifica ligeramante la lógica para ilustrar cambios en la estructura del código.


package org.springframework.web.servlet.handler;  
import java.io.IOException;  
import javax.servlet.ServletException;  
import javax.servlet.http.HttpServletRequest;  
import javax.servlet.http.HttpServletResponse;  
public class InterceptorAutorizacionRol extends BaseInterceptor {  
    private String[] rolesPermitidos;  
    public final void setRolesPermitidos(String[] roles) {  
        this.rolesPermitidos = roles;  
    }  
    public final boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object handler)  
      throws ServletException, IOException {  
        if (this.rolesPermitidos != null) {  
            for (String rol : this.rolesPermitidos) {  
                if (req.isUserInRole(rol)) {  
                    return true;  
                }  
            }  
        }  
        manejarNoAutorizado(req, resp, handler);  
        return false;  
    }  
    protected void manejarNoAutorizado(HttpServletRequest req, HttpServletResponse resp, Object handler)  
      throws ServletException, IOException {  
          resp.sendError(403);  
    }  
}  

Para un interceptor de inicio de sesión personalizado, se utiliza HandlerInterceptorAdapter con lógica adaptada. Se renombran variables y se ajusta el flujo para reducir similitud con el código original.


import java.util.HashMap;  
import java.util.Map;  
import javax.servlet.http.HttpServletRequest;  
import javax.servlet.http.HttpServletResponse;  
import org.springframework.web.servlet.ModelAndView;  
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;  
public class InterceptorLoginSpring extends HandlerInterceptorAdapter {  
    public boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object handler) throws Exception {  
        if ("GET".equalsIgnoreCase(req.getMethod())) {  
            // Guardar solicitud si es necesario  
        }  
        String uriSolicitud = req.getRequestURI();  
        String rutaContexto = req.getContextPath();  
        String urlRelativa = uriSolicitud.substring(rutaContexto.length());  
        String nombreUsuario = (String) req.getSession().getAttribute("usuario");  
        if (null == nombreUsuario) {  
            req.getRequestDispatcher("/WEB-INF/vista_login.jsp").forward(req, resp);  
            return false;  
        }  
        return true;  
    }  
    public void postHandle(HttpServletRequest req, HttpServletResponse resp, Object handler, ModelAndView modelAndView) throws Exception {  
        if (modelAndView != null) {  
            Map<string string=""> datos = new HashMap<>();  
            modelAndView.addAllObjects(datos);  
        }  
    }  
    public void afterCompletion(HttpServletRequest req, HttpServletResponse resp, Object handler, Exception ex) throws Exception {  
        // Limpieza de recursos  
    }  
}  
</string>

Configuración en Spring MVC

Para registrar interceptores en Spring MVC, se modifica el archivo de configuración, como spring-mvc.xml, definiendo reglas de intercepción y exclusiones.


<!-- Configuración de interceptores -->
<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/**" />
        <mvc:exclude-mapping path="/login.html" />
        <mvc:exclude-mapping path="/cuenta/acceder.do" />
        <mvc:exclude-mapping path="/cuenta/registrar.do" />
        <bean class="com.ejemplo.interceptor.InterceptorLoginSpring" />
    </mvc:interceptor>
</mvc:interceptors>

Resumen Técnico

Los filtros en Java proporcionan filtrado a nivel de solicitudes web, útiles para tareas como configurar codificación o bloquear URLs no autorizadas. Los listeners responden a eventos del ciclo de vida de la aplicación, como el inicio o cierre de sesiones. Los interceptores, por otro lado, se enfocan en la intercepción de métodos y se integran en frameworks como Spring y Hibernate para extender funcionalidades mediante AOP, ofreciendo un control más granular sobre la lógica de negocio.

Etiquetas: java spring-mvc interceptor AOP servlet

Publicado el 6-12 21:09