Skip to content

Filter 过滤器

Filter 是 Servlet 规范中的组件,在请求到达 Servlet(Controller)之前之后对请求/响应进行处理。

一、执行流程

text
Client ──→ Filter ──→ Filter ──→ DispatcherServlet ──→ Interceptor ──→ Controller
  ↑          ↑            ↑
  └── 响应按逆序经过各 Filter ───────────────────────────────────────────┘

二、Filter 生命周期方法

java
public interface Filter {

    // Filter 被创建时调用(只执行一次),用于初始化
    default void init(FilterConfig filterConfig) throws ServletException {}

    // 每次拦截到请求时调用
    void doFilter(ServletRequest request, ServletResponse response,
                  FilterChain chain) throws IOException, ServletException;

    // Filter 被销毁时调用(只执行一次)
    default void destroy() {}
}

参数说明

方法参数类型说明
requestServletRequest请求对象,可强制转换为 HttpServletRequest
responseServletResponse响应对象,可强制转换为 HttpServletResponse
chainFilterChain过滤器链,必须调用 chain.doFilter() 放行
filterConfigFilterConfigFilter 配置对象(初始化参数)

三、自定义 Filter

3.1 实现 Filter 接口

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

@Component
public class LogFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 初始化逻辑(如读取配置参数)
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        String uri = httpRequest.getRequestURI();
        System.out.println("请求进入 Filter → " + uri);

        long start = System.currentTimeMillis();
        chain.doFilter(request, response);  // ❗ 必须调用放行
        long end = System.currentTimeMillis();

        System.out.println("请求处理完成 → " + uri + ",耗时:" + (end - start) + "ms");
    }

    @Override
    public void destroy() {
        // 销毁逻辑(应用关闭时释放资源)
    }
}

如果未调用 chain.doFilter(),请求将被阻断,Controller 不会执行。

3.2 继承 OncePerRequestFilter

Spring 提供的便捷基类,保证每个请求只经过一次过滤(解决内部 forward 导致重复过滤的问题)。推荐使用。

java
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class AuthFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain)
                                    throws ServletException, IOException {
        String token = request.getHeader("X-Token");
        if (token == null || token.isEmpty()) {
            response.setStatus(401);
            response.getWriter().write("{\"code\":401,\"message\":\"未登录\"}");
            return;  // 不放行,直接返回
        }
        filterChain.doFilter(request, response);
    }

    // 排除不需要过滤的路径(可选)
    @Override
    protected boolean shouldNotFilter(HttpServletRequest request) {
        String path = request.getRequestURI();
        return path.startsWith("/public/") || path.startsWith("/login");
    }
}

3.3 实现 Ordered 接口

多个 Filter 需要控制执行顺序时实现:

java
@Component
public class FirstFilter extends OncePerRequestFilter implements Ordered {

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain) {
        // 业务逻辑
        filterChain.doFilter(request, response);
    }

    @Override
    public int getOrder() {
        return 1; // 值越小优先级越高
    }
}

四、注册 Filter 的三种方式

方式一:@Component 直接注册

java
@Component
public class MyFilter implements Filter { ... }

最简单的方式,但拦截路径默认为 /*,无法自定义。

方式二:FilterRegistrationBean(推荐)

在配置类中通过 FilterRegistrationBean 手动注册,精确控制路径和顺序

java
@Configuration
public class FilterConfig {

    @Bean
    public FilterRegistrationBean<AuthFilter> authFilterRegistration() {
        FilterRegistrationBean<AuthFilter> registration = new FilterRegistrationBean<>();
        registration.setFilter(new AuthFilter());
        registration.addUrlPatterns("/api/*");         // 拦截路径
        registration.setOrder(1);                      // 执行顺序
        registration.setName("authFilter");            // Filter 名称
        registration.addInitParameter("excludeUrls", "/api/login,/api/public");
        return registration;
    }
}
FitlerRegistrationBean 参数类型说明
addUrlPatternsString...拦截的 URL 模式
setOrderint执行顺序,值越小越优先
setNameStringFilter 名称
addInitParameterString, String初始化参数(通过 FilterConfig 获取)
setDispatcherTypesEnumSet<DispatcherType>调度类型:REQUEST/FORWARD/INCLUDE/ERROR/ASYNC

方式三:@WebFilter + @ServletComponentScan

java
@WebFilter(urlPatterns = "/api/*", filterName = "authFilter")
public class AuthFilter extends OncePerRequestFilter { ... }

// 启动类上添加 ↓
@SpringBootApplication
@ServletComponentScan("com.example.filter")
public class Application { ... }

对比

方式路径控制顺序控制推荐场景
@Component默认 /*不支持简单过滤
FilterRegistrationBean✅ 精确✅ 精确推荐,生产级
@WebFilter注解配置@Order简单场景

五、Filter vs Interceptor

维度FilterInterceptor
规范Servlet 规范Spring 框架
作用范围所有请求(含静态资源)仅经过 DispatcherServlet 的请求
依赖注入不支持 @Autowired支持 Spring Bean 注入
功能请求/响应包装、编码、安全权限校验、日志、性能监控
执行顺序先于 Interceptor后于 Filter

六、速查表

类/接口用途
javax.servlet.FilterFilter 接口,需实现 doFilter()
OncePerRequestFilterSpring 提供,保证单次执行(推荐)
FilterChain过滤器链,调用 doFilter() 放行
FilterRegistrationBean精确注册 Filter(路径/顺序)
Ordered控制多个 Filter 执行顺序
@WebFilterServlet 注解方式注册 Filter
@ServletComponentScan配合 @WebFilter 扫描包路径
最近更新