拦截器模式

拦截器模式

目录背景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 链,可以显著提升代码的可维护性和扩展性,同时保持核心业务逻辑的简洁性。

参考资料