¿Qué es un filtro (Filter)?
Un filtro es una función de especificación estándar de J2EE que proporciona la capacidad de procesar tareas adicionales para todas las solicitudes que coincidan con un patrón de URL antes/después de que la solicitud se envíe al servlet despachador (Dispatcher Servlet). En otras palabras, es administrado por un contenedor web como Tomcat, no por el contenedor Spring, por lo que procesa la solicitud antes de que llegue al servlet despachador.
Implementación del filtro (Filter)
Para agregar un filtro, debe implementar la interfaz Filter de javax.servlet, que tiene los siguientes tres métodos.
- Método init
- Es un método para inicializar el objeto filtro y agregarlo al servicio. El contenedor web llama al método init una vez para inicializar el objeto filtro, y luego las solicitudes subsiguientes se procesan a través del método doFilter().
- Método doFilter
- Es un método que se ejecuta por el contenedor web antes de que todas las solicitudes HTTP que coincidan con el patrón de URL se envíen al servlet despachador y antes de que el servlet despachador envíe la respuesta HTTP al cliente.
El parámetro del método doFilter() es FilterChain, y la solicitud se reenvía al siguiente destino a través de doFilter() de FilterChain. Al agregar el proceso que necesitamos antes/después de chain.doFilter(), podemos realizar el procesamiento deseado.
- Es un método que se ejecuta por el contenedor web antes de que todas las solicitudes HTTP que coincidan con el patrón de URL se envíen al servlet despachador y antes de que el servlet despachador envíe la respuesta HTTP al cliente.
- Método destroy
- Es un método para eliminar el objeto filtro del servicio y devolver los recursos utilizados. El contenedor web lo llama una vez, y luego ya no se procesa a través de doFilter().
Código de ejemplo - Especificación Servlet
Código de ejemplo - @Component
- @Component: Permite registrar el filtro como un bean de Spring.
- @Order: Permite establecer el orden cuando hay varios filtros.
- Si registra el filtro correspondiente a la especificación del servlet como un bean de Spring de esta manera, puede usar otros beans correspondientes a la especificación de Spring.
Código de ejemplo - @Configuration
Si desea que el filtro solo funcione para una URI específica, puede registrar el filtro como un bean de Spring usando FilterRegistrationBean.
Propósito del filtro (Filter)
Principalmente se encarga de la validación y el procesamiento de los propios parámetros de la solicitud.
- Tareas comunes relacionadas con la seguridad
- Dado que el filtro funciona en el contenedor web, puede realizar una verificación de seguridad (prevención de XSS, CSRF, etc.) y bloquear las solicitudes incorrectas. Dado que la solicitud no se envía al contenedor Spring y se bloquea, se puede mejorar aún más la estabilidad.
- Registro de todas las solicitudes
- Compresión de imágenes/datos y codificación de caracteres
- El filtro implementó funciones que se utilizan ampliamente en las aplicaciones web, como la compresión de imágenes o datos y la codificación de caracteres.
- Personalización de ServletRequest
- HttpServletRequest solo puede leer el contenido del cuerpo una vez. Por lo tanto, Filter o Interceptor no pueden leer el cuerpo. Se puede crear un ServletRequest personalizado para registrar el cuerpo.
Interceptor (Interceptador)
¿Qué es un interceptor (Interceptor)?
A diferencia del filtro (Filter), que es una especificación estándar de J2EE, el interceptor (Interceptor) es una tecnología proporcionada por Spring que proporciona la capacidad de referenciar o procesar solicitudes y respuestas antes y después de que el servlet despachador llame al controlador. En otras palabras, a diferencia del filtro que funciona en el contenedor web, el interceptor funciona en el contexto de Spring.
El servlet despachador solicita al controlador adecuado a través del mapeo del controlador, y devuelve la cadena de ejecución (HandlerExecutionChain) como resultado. Por lo tanto, si hay uno o más interceptores registrados en esta cadena de ejecución, se ejecutan secuencialmente a través del interceptor antes de que se ejecute el controlador, y si no hay ningún interceptor, el controlador se ejecuta directamente.
Implementación del interceptor (Interceptor)
Para agregar un interceptor, debe implementar la interfaz HandlerInterceptor de org.springframework.web.servlet, que tiene los siguientes tres métodos.
- Método preHandle
- El método preHandle se ejecuta antes de que se llame al controlador. Por lo tanto, se puede utilizar para tareas de preprocesamiento que deben procesarse antes del controlador o para procesar o agregar información de solicitud.
- El tercer parámetro del método preHandle, el parámetro handler, es un objeto que abstrae la información del método al que se adjunta @RequestMapping.
- El tipo de retorno del método preHandle es booleano. Si el valor devuelto es verdadero, se procede a la siguiente etapa, pero si es falso, se detiene la operación y no se ejecutan las operaciones posteriores (siguiente interceptor o controlador).
- Método postHandle
- El método postHandle se ejecuta después de que se llama al controlador. Por lo tanto, se puede usar cuando hay tareas de postprocesamiento que deben procesarse después del controlador.
- Método afterCompletion
- Como su nombre lo indica, el método afterCompletion se ejecuta después de que se completa todo el trabajo, incluida la generación del resultado final en todas las vistas.
Código de ejemplo
- Registre el interceptor creado como un bean.
- Registre el interceptor creado en el método addInterceptors() de la interfaz WebMvcConfigurer.
- Los interceptores funcionan en el orden en que se registran en InterceptorRegistry.
Propósito del interceptor (Interceptor)
Principalmente se encarga de procesar la coherencia de la información de la solicitud utilizando la lógica del servicio.
- Tareas comunes como la autenticación/autorización
- Como ejemplo típico, puede verificar tareas relacionadas con la solicitud del cliente, como la autenticación o la autorización, antes de que pasen al controlador.
- Registro de llamadas a la API
- Puede registrar información del cliente a través de los objetos HttpServletRequest y HttpServletResponse que recibe.
- Procesamiento de datos que se pasan al controlador
- Puede procesar los objetos HttpServletRequest y HttpServletResponse que recibe y pasarlos al controlador.
- Simulación de AOP
- Puede verificar el tercer parámetro del método preHandle, HandlerMethod, para obtener información adicional como la firma del método que se ejecutará y determinar si se ejecutará la lógica.
Filtro (Filter) vs. Interceptor (Interceptador)
- El filtro se ejecuta en el contexto web y el interceptor se ejecuta en el contexto de Spring, por lo que el momento de ejecución es diferente.
- El filtro puede controlar antes y después del servlet despachador, mientras que el interceptor puede controlar antes y después del controlador.
- Es mejor usar filtros para tareas que deben procesarse globalmente independientemente de Spring, o para validar los propios parámetros de entrada, o cuando se usa ServletRequest en lugar de HttpServletRequest.
- Es mejor usar interceptores para tareas que deben procesarse globalmente relacionadas con la solicitud del cliente en la unidad Spring o cuando se debe mezclar la lógica del servicio.
- El interceptor puede manejar excepciones utilizando @ControllerAdvice y @ExceptionHandler, pero el filtro no puede usarlas para manejar excepciones.
- El filtro generalmente envuelve el método doFilter() con una cláusula try~catch para manejar inmediatamente las excepciones que ocurren en ese momento.
Argument Resolver
¿Qué es Argument Resolver?
Argument Resolver puede ayudar indirectamente a crear el objeto deseado a partir del valor que ingresa en la solicitud cuando llega una solicitud al controlador.
Propósito de Argument Resolver
Por ejemplo, supongamos que una solicitud llega con un token JWT. Necesitamos verificar si este token es válido y luego extraer el ID almacenado en el token para crearlo como un objeto de usuario de inicio de sesión.
En este caso, si no usa Argument Resolver, debe implementar el proceso de verificación del token y la conversión a un objeto de usuario de inicio de sesión en cada controlador. Esto genera código duplicado en los controladores donde se requiere la verificación del usuario y aumenta la responsabilidad del controlador. Argument Resolver puede resolver este problema.
Implementación de Argument Resolver
Argument Resolver se puede usar implementando HandlerMethodArgumentResolver. Esta interfaz especifica que se deben implementar los siguientes dos métodos.
- Método supportsParameter
- Crea y adjunta una anotación específica antes del parámetro para el que desea que se ejecute Argument Resolver. El método supportsParameter() verifica si el método solicitado tiene la anotación deseada y devuelve verdadero si la incluye.
- Método resolveArgument
- Si se recibe verdadero en supportsParameter, es decir, si hay un método con una anotación específica, es un método que devuelve el parámetro al vincular la información en el formato deseado.
Si usa Argument Resolver de esta manera, la implementación del controlador es la siguiente.
Diferencias entre Argument Resolver e Interceptor (Interceptador)
- Argument Resolver funciona después del interceptor y devuelve el objeto deseado a partir del valor que ingresa en la solicitud cuando llega una solicitud al controlador.
- Por otro lado, el interceptor intercepta la solicitud antes de que se ejecute el controlador real y no puede devolver ningún objeto. Solo existen tipos de retorno booleano o vacío.
Fuentes
- https://mangkyu.tistory.com/173
- https://junhyunny.github.io/spring-boot/filter-interceptor-and-aop/
- https://supawer0728.github.io/2018/04/04/spring-filter-interceptor/
- https://tecoble.techcourse.co.kr/post/2021-05-24-spring-interceptor/
- https://baeldung-cn.com/spring-mvc-handlerinterceptor-vs-filter
- https://www.baeldung.com/spring-boot-add-filter
Preguntas y respuestas de la entrevista esperadas
¿Qué es un filtro?
Un filtro es una función que proporciona la capacidad de procesar tareas adicionales para todas las solicitudes que coincidan con un patrón de URL antes/después de que la solicitud se envíe al servlet despachador y funciona en el contenedor de servlets.
¿Cuándo se utiliza un filtro?
Los filtros se pueden utilizar para procesar tareas que deben procesarse globalmente independientemente de Spring. O se usa cuando se verifica un parámetro de solicitud.
Principalmente procesa tareas comunes relacionadas con la seguridad, registro de todas las solicitudes, compresión de imágenes/datos y codificación de caracteres, y tareas de personalización de ServletRequest.
¿Qué es un interceptor?
Un interceptor es una función que proporciona la capacidad de referenciar o procesar solicitudes y respuestas antes y después de que el servlet despachador llame al controlador y funciona en el contenedor de Spring.
¿Cuándo se utiliza un interceptor?
Los interceptores se pueden usar para procesar tareas que deben procesarse globalmente relacionadas con la solicitud del cliente. Principalmente se utiliza cuando se llama a la lógica del servicio durante la validación.
Principalmente procesa tareas comunes como la autenticación/autorización, el registro de llamadas a la API y el procesamiento de datos que se pasan al controlador.
¿Cuál es la diferencia entre un filtro y un interceptor?
Los filtros se ejecutan en el contenedor de servlets y los interceptores se ejecutan en el contenedor de Spring.
Los filtros pueden controlar antes y después del servlet despachador, mientras que los interceptores pueden controlar antes y después del controlador.
Por lo tanto, es mejor usar filtros para tareas que deben procesarse globalmente independientemente de Spring, y es mejor usar interceptores para tareas que deben procesarse globalmente relacionadas con la solicitud del cliente.
¿Qué es Argument Resolver?
Argument Resolver ayuda indirectamente a crear el objeto deseado a partir del valor que ingresa en la solicitud cuando llega una solicitud al controlador.
¿Cuándo se utiliza Argument Resolver?
Se puede utilizar cuando llega una solicitud con un token JWT, se verifica si el token es válido y luego se extrae el ID almacenado en el token para crearlo como un objeto LoginMember.
¿Cuál es la diferencia entre un interceptor y Argument Resolver?
Argument Resolver devuelve el objeto deseado a partir del valor que ingresa en la solicitud cuando llega una solicitud al controlador. Por otro lado, el interceptor no puede devolver un objeto de esa manera, y Argument Resolver se ejecuta después de que se ejecuta el interceptor.
Comentarios0