Filtros e Interceptadores no Spring MVC: Conceitos e Implementação

No ecossistema Spring MVC, o ciclo de vida de uma requisição HTTP atravsesa diversas camadas antes de atingir o controlador e retornar a resposta ao cliente. Inicialmente, a requisição passa pela cadeia de Filtros (Filters), executando o método doFilter() de cada compoennte configurado. Em seguida, entra no método service() do Servlet e é encaminhada pelo DispatcherServlet para o Controlador mapeado. Antes da execução do método do Controlador, o Interceptador (Interceptor) executa preHandle(). Após a execução do Controlador e antes da resolução da visualização, postHandle() é invocado. Por fim, afterCompletion() é chamado após a renderização, e o fluxo retorna pela cadeia de Filtros para processar a resposta final.

Filtros (Filters) no Nível do Servlet

Os Filtros operam no nível do contêiner Servlet, interceptando objetos HttpServletRequest e HttpServletResponse. Eles possuem um escopo mais amplo e são ideais para tarefas transversais como validação de tokens de segurança, configuração de cabeçalhos CORS, compressão de dados e bloqueio de requisições maliciosas. Um filtro implementa a interface Filter e gerencia seu ciclo de vida através dos métodos init(), doFilter() e destroy(), sendo inicializado e destruído junto com o contêiner.

Exemplo de implementação de um filtro de autenticação:

package com.exemplo.app.seguranca;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

public class FiltroAutenticacao implements Filter {

    @Override
    public void init(FilterConfig config) throws ServletException {
        System.out.println("Inicializando o filtro de autenticação...");
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) 
            throws IOException, ServletException {
        
        HttpServletRequest httpReq = (HttpServletRequest) req;
        String token = httpReq.getHeader("Authorization");
        
        // Lógica de validação do token de acesso
        System.out.println("Validando credenciais para a URI: " + httpReq.getRequestURI());
        
        // Continua a cadeia de filtros
        chain.doFilter(req, res);
    }

    @Override
    public void destroy() {
        System.out.println("Encerrando o filtro de autenticação.");
    }
}

Para registrar este filtro no contexto do Spring Boot e integrá-lo ao contêiner, utilizamos o FilterRegistrationBean:

package com.exemplo.app.configuracao;

import com.exemplo.app.seguranca.FiltroAutenticacao;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ConfiguracaoFiltros {

    @Bean
    public FilterRegistrationBean<FiltroAutenticacao> registrarFiltroAutenticacao() {
        FilterRegistrationBean<FiltroAutenticacao> registro = new FilterRegistrationBean<>();
        registro.setFilter(new FiltroAutenticacao());
        registro.addUrlPatterns("/api/*");
        registro.setName("filtroDeAutenticacao");
        registro.setOrder(1);
        return registro;
    }
}

Interceptadores (Interceptors) no Nível do Spring

Diferente dos filtros, os Interceptadores são componentes nativos do framework Spring e não dependem do contêiner Servlet. Baseados no paradigma de Programação Orientada a Aspectos (AOP), eles permitem interceptar chamadas de métodos específicos dos Controladores com uma granularidade muito maior. Por estarem integrados ao contexto Spring, podem injetar e utilizar outros beans gerenciados. A interface principal é a HandlerInterceptor, que fornece os métodos preHandle(), postHandle() e afterCompletion().

Exemplo de um interceptador para registro de métricas e logs de execução:

package com.exemplo.app.interceptadores;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class InterceptadorDeLog implements HandlerInterceptor {

    private static final Logger log = LoggerFactory.getLogger(InterceptadorDeLog.class);

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        log.info("Iniciando processamento do endpoint: {}", request.getRequestURI());
        request.setAttribute("inicioExecucao", System.currentTimeMillis());
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
        log.info("Processamento do endpoint concluído, preparando a resposta.");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        long inicio = (Long) request.getAttribute("inicioExecucao");
        long duracao = System.currentTimeMillis() - inicio;
        log.info("Tempo total de execução para {}: {} ms", request.getRequestURI(), duracao);
    }
}

O registro do interceptador é feito implementando a interface WebMvcConfigurer e sobrescrevendo o método de configuração:

package com.exemplo.app.configuracao;

import com.exemplo.app.interceptadores.InterceptadorDeLog;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class ConfiguracaoWebMvc implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new InterceptadorDeLog())
                .addPathPatterns("/api/**")
                .excludePathPatterns("/api/publico/**");
    }
}

Tags: spring-mvc java filters interceptors servlet-api

Publicado em 6-2 20:55 por Thomas