@WebFilter 过滤器的执行顺序
@WebFilter 过滤器的执行顺序
1. 默认执行顺序(不可靠!)
当只使用 @WebFilter
注解而没有其他配置时,过滤器的执行顺序是不确定的。
- 它取决于容器(如 Tomcat)的类加载机制
- 通常与类名的字母顺序或文件系统顺序有关,但这不是官方规范
- 不同服务器或不同环境下顺序可能变化
// 示例:两个过滤器的执行顺序不确定
@WebFilter("/*")
public class FilterA implements Filter {// 可能先执行,也可能后执行
}@WebFilter("/*")
public class FilterB implements Filter {// 可能先执行,也可能后执行
}
2. 控制执行顺序的可靠方法
方法一:使用 web.xml
配置(最可靠)
在 web.xml
中明确指定过滤器的顺序:
<?xml version="1.0" encoding="UTF-8"?>
<web-app><!-- 声明过滤器 --><filter><filter-name>EncodingFilter</filter-name><filter-class>com.example.EncodingFilter</filter-class></filter><filter><filter-name>AuthFilter</filter-name><filter-class>com.example.AuthFilter</filter-class></filter><filter><filter-name>LoggingFilter</filter-name><filter-class>com.example.LoggingFilter</filter-class></filter><!-- 映射顺序决定了执行顺序 --><filter-mapping><filter-name>EncodingFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping><filter-mapping><filter-name>AuthFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping><filter-mapping><filter-name>LoggingFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping>
</web-app>
执行顺序(过滤器链):
EncodingFilter
→ 2.AuthFilter
→ 3.LoggingFilter
→ Servlet
响应时的反向顺序:
Servlet → LoggingFilter
→ AuthFilter
→ EncodingFilter
→ 客户端
方法二:使用 @Order
注解(Servlet 3.0+)
import javax.annotation.Priority;
import javax.servlet.annotation.WebFilter;@WebFilter("/*")
@Priority(1) // 或者使用 @Order(1)
public class EncodingFilter implements Filter {// 数字越小,优先级越高,越先执行
}@WebFilter("/*")
@Priority(2)
public class AuthFilter implements Filter {// 第二个执行
}@WebFilter("/*")
@Priority(3)
public class LoggingFilter implements Filter {// 最后一个执行
}
方法三:通过 URL 模式的特异性控制
容器会优先匹配更具体的 URL 模式:
@WebFilter("/admin/*") // 更具体,先执行
public class AdminFilter implements Filter {}@WebFilter("/*") // 更通用,后执行
public class GlobalFilter implements Filter {}
3. 完整的执行流程示例
// 过滤器A:字符编码过滤器
@WebFilter("/*")
public class EncodingFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {System.out.println("1. EncodingFilter - 前处理");request.setCharacterEncoding("UTF-8");// 调用过滤器链中的下一个组件chain.doFilter(request, response);System.out.println("4. EncodingFilter - 后处理");}
}// 过滤器B:日志记录过滤器
@WebFilter("/*")
public class LoggingFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {System.out.println("2. LoggingFilter - 前处理");long startTime = System.currentTimeMillis();chain.doFilter(request, response);long endTime = System.currentTimeMillis();System.out.println("3. LoggingFilter - 后处理,耗时:" + (endTime - startTime) + "ms");}
}
4. 执行顺序总结表
控制方式 | 可靠性 | 使用场景 | 备注 |
---|---|---|---|
web.xml 配置 | ★★★★★ | 生产环境,需要严格顺序 | 最可靠,顺序明确 |
@Order / @Priority | ★★★★ | Servlet 3.0+ 项目 | 较可靠,但要注意容器支持 |
URL 模式特异性 | ★★★ | 按功能模块划分 | 利用匹配规则,不够灵活 |
类名顺序 | ★ | 测试环境 | 绝对不要在生产环境依赖 |
5. 最佳实践建议
- 生产环境:优先使用
web.xml
配置执行顺序 - 明确依赖:如果过滤器间有依赖关系,一定要显式配置顺序
- 测试验证:部署前务必测试过滤器的执行顺序是否符合预期
- 避免隐式依赖:不要依赖不确定的默认顺序
// 好的实践:在过滤器注释中明确说明顺序依赖
/*** 字符编码过滤器* 执行顺序:应该在其他过滤器之前执行* 依赖:无*/
@WebFilter("/*")
public class EncodingFilter implements Filter {// ...
}
记住:显式配置优于隐式约定,这对于过滤器顺序尤为重要!