FilterChain 详解

FilterChain 详解

FilterChain(过滤器链)是 JavaWeb 中多个 Filter 协同工作的机制,它决定了请求通过多个 Filter 的顺序以及最终如何到达目标资源。


一、FilterChain 核心概念

  1. 链式结构:多个 Filter 按配置顺序形成处理链
  2. 责任链模式:每个 Filter 处理请求后决定是否传递给下一个 Filter
  3. 双向处理:请求进入时正向处理,响应返回时反向处理

二、FilterChain 工作原理

执行流程图示

客户端请求 → Filter1 → Filter2 → ... → FilterN → Servlet → FilterN → ... → Filter2 → Filter1 → 客户端响应

代码层面流程

// 伪代码展示FilterChain执行逻辑
public void doFilter(ServletRequest request, ServletResponse response) {
    if (hasNextFilter()) {
        nextFilter.doFilter(request, response); // 传递给下一个Filter
    } else {
        servlet.service(request, response); // 最终到达Servlet
    }
    // 响应返回时的处理
}

三、FilterChain 关键特性

1. Filter执行顺序控制

1.1 使用注解进行配置时:无明确顺序(可用 @Order 注解在某些框架中指定)
1.2 使用web.xml进行配置时:以Tomcat为例。首先收集所有匹配的Filter映射,然后按以下规则排序:
①首先按URL pattern类型排序(精确 > 路径 > 扩展名)
②同类型按web.xml中出现的顺序
③注解注册的Filter顺序由容器实现决定
④排除重复Filter(相同Filter只执行一次)

2. 中断机制

  • 不调用 chain.doFilter():中断链,请求不会继续传递
    public void doFilter(...) {
        if (!isAuthenticated(request)) {
            response.sendError(403); // 中断链
            return;
        }
        chain.doFilter(request, response); // 继续执行
    }
    

3. 请求/响应包装

  • 可包装请求/响应对象
    public void doFilter(...) {
        HttpServletRequest wrappedRequest = new CustomRequestWrapper(request);
        HttpServletResponse wrappedResponse = new CustomResponseWrapper(response);
        chain.doFilter(wrappedRequest, wrappedResponse);
    }
    

四、FilterChain 实际应用

1. 典型过滤器链配置

<!-- web.xml 示例 -->
<filter-mapping>
    <filter-name>EncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<filter-mapping>
    <filter-name>SecurityFilter</filter-name>
    <url-pattern>/secure/*</url-pattern>
</filter-mapping>

<filter-mapping>
    <filter-name>LoggingFilter</filter-name>
    <url-pattern>*.do</url-pattern>
</filter-mapping>

2. 多过滤器协作示例

// 编码过滤器
public class EncodingFilter implements Filter {
    public void doFilter(...) {
        request.setCharacterEncoding("UTF-8");
        chain.doFilter(request, response);
    }
}

// 认证过滤器
public class AuthFilter implements Filter {
    public void doFilter(...) {
        if (checkAuth(request)) {
            chain.doFilter(request, response);
        } else {
            response.sendRedirect("/login");
        }
    }
}

// 日志过滤器
public class LogFilter implements Filter {
    public void doFilter(...) {
        long start = System.currentTimeMillis();
        chain.doFilter(request, response);
        long duration = System.currentTimeMillis() - start;
        logRequest(request, duration);
    }
}

五、高级应用技巧

1. 动态控制过滤器链

public void doFilter(...) {
    if (shouldSkipFilter(request)) {
        chain.doFilter(request, response); // 跳过当前过滤逻辑
    } else {
        // 正常过滤处理
        processRequest(request);
        chain.doFilter(request, response);
        processResponse(response);
    }
}

2. 过滤器间数据传递

// 前一个过滤器设置属性
request.setAttribute("filterData", data);

// 后一个过滤器获取属性
Object data = request.getAttribute("filterData");

3. 异步请求处理

@WebFilter(asyncSupported = true)
public class AsyncFilter implements Filter {
    public void doFilter(...) {
        AsyncContext asyncCtx = request.startAsync();
        asyncCtx.addListener(new AsyncListener() {
            // 异步回调处理
        });
        chain.doFilter(request, response);
    }
}

六、常见问题解决方案

1. 执行顺序问题

问题:注解配置的过滤器顺序不可控
解决

  • 使用 web.xml 显式配置顺序
  • 使用框架提供的排序机制(如 Spring 的 @Order

2. 性能优化

建议

  • 在 Filter 中缓存常用数据
  • 避免在 Filter 中执行耗时操作
  • 合理设计 Filter 链长度

3. 异常处理

最佳实践

public void doFilter(...) {
    try {
        chain.doFilter(request, response);
    } catch (Exception e) {
        // 统一异常处理
        handleException(e, response);
    }
}

七、FilterChain 与拦截器对比

特性FilterChain拦截器(如Spring Interceptor)
所处层次Servlet 容器层面MVC 框架层面
执行时机更早(在DispatcherServlet之前)稍晚(进入Controller之前)
依赖仅依赖Servlet API依赖特定框架
配置方式web.xml 或 @WebFilter框架配置机制
访问控制粒度粗粒度(URL模式)细粒度(可精确到Controller方法)
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值