目录背景1. 拦截器模式的核心思想2. Filter 的典型应用场景(1) 全局字符编码过滤(2) 登录校验过滤(3) 日志记录过滤3. 用好 Filter 的最佳实践(1) 单一职责原则(2) 控制执行顺序(3) 异步支持(4) 资源管理(5) 异常处理4. 进阶技巧(1) 动态过滤路径(2) CORS 处理(3) 请求/响应修改5. 注意事项参考资料
背景
拦截器模式是一种行为设计模式,允许在不修改原有对象的情况下,在其前后插入额外的逻辑。Filter 在 Servlet 中的应用正是这一模式的典型体现:
前置处理:在请求到达目标资源(如 Servlet、JSP)之前,对请求进行预处理(如字符编码、权限校验)。
后置处理:在响应返回客户端之前,对响应进行加工(如压缩、日志记录)。
Servlet Filter 使用的设计模式:拦截器模式(Interceptor Pattern)
1. 拦截器模式的核心思想
拦截器模式是一种行为设计模式,允许在不修改原有对象的情况下,在其前后插入额外的逻辑。Filter 在 Servlet 中的应用正是这一模式的典型体现:
前置处理:在请求到达目标资源(如 Servlet、JSP)之前,对请求进行预处理(如字符编码、权限校验)。
后置处理:在响应返回客户端之前,对响应进行加工(如压缩、日志记录)。
2. Filter 的典型应用场景
(1) 全局字符编码过滤
@WebFilter("/*")
public class EncodingFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
req.setCharacterEncoding("UTF-8");
res.setCharacterEncoding("UTF-8");
chain.doFilter(req, res);
}
}
(2) 登录校验过滤
@WebFilter("/secure/*")
public class AuthFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
if (request.getSession().getAttribute("user") == null) {
response.sendRedirect(request.getContextPath() + "/login");
} else {
chain.doFilter(req, res);
}
}
}
(3) 日志记录过滤
@WebFilter("/*")
public class LogFilter implements Filter {
private Logger logger = LoggerFactory.getLogger(LogFilter.class);
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
String uri = ((HttpServletRequest) req).getRequestURI();
logger.info("Request: {} - {}", LocalDateTime.now(), uri);
chain.doFilter(req, res);
logger.info("Response: {} - {}", LocalDateTime.now(), uri);
}
}
3. 用好 Filter 的最佳实践
(1) 单一职责原则
每个 Filter 专注一个功能(如编码、鉴权、日志),避免功能混杂。
示例:拆分 EncodingFilter 和 SecurityFilter。
(2) 控制执行顺序
通过 @WebFilter 的 order 属性或 web.xml 的
关键场景:字符编码过滤器应放在最前端。
(3) 异步支持
对耗时操作(如数据库查询)使用 AsyncContext,避免阻塞主线程:
chain.doFilter(req, res); // 同步调用
// 或
AsyncContext asyncContext = req.startAsync();
asyncContext.start(() -> {
// 异步处理逻辑
});
(4) 资源管理
在 init() 中加载配置,在 destroy() 中释放资源(如数据库连接池):
@Override
public void init(FilterConfig config) throws ServletException {
// 初始化配置
}
@Override
public void destroy() {
// 释放资源
}
(5) 异常处理
捕获 Filter 链中的异常并统一处理:
try {
chain.doFilter(req, res);
} catch (Exception e) {
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Error occurred");
}
4. 进阶技巧
(1) 动态过滤路径
通过注解参数动态匹配路径:
@WebFilter(urlPatterns = {"${config.loginPath}"})
public class DynamicFilter implements Filter { /* ... */ }
(2) CORS 处理
@WebFilter("/*")
public class CorsFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE");
chain.doFilter(req, res);
}
}
(3) 请求/响应修改
修改请求参数(需谨慎):
HttpServletRequestWrapper requestWrapper = new HttpServletRequestWrapper(req) {
@Override
public String getParameter(String name) {
return super.getParameter(name).toUpperCase();
}
};
chain.doFilter(requestWrapper, res);
5. 注意事项
性能影响:避免在 Filter 中进行 IO 操作或复杂计算。
安全风险:敏感操作(如密码验证)应在 Filter 之后由业务层处理。
依赖注入:可通过 @Inject 注入 Spring Bean(需启用 @WebFilter + @Component)。
通过合理设计 Filter 链,可以显著提升代码的可维护性和扩展性,同时保持核心业务逻辑的简洁性。
参考资料