拦截过滤器模式
拦截过滤器模式(Intercepting Filter Pattern)是一种企业级设计模式,用于在请求到达目标处理程序之前或响应返回客户端之前,对请求或响应进行预处理或后处理。它通过一系列可插拔的过滤器(Filters)实现请求的拦截和处理,提供了灵活的机制来执行认证、日志记录、数据转换等操作,常用于 Web 应用程序(如 Java EE 的 Servlet 过滤器)。
拦截过滤器模式的组成
拦截过滤器模式通常包含以下几个角色:
- 过滤器(Filter):定义拦截逻辑的接口,包含处理请求或响应的方法。
- 具体过滤器(Concrete Filter):实现过滤器接口,执行特定的预处理或后处理逻辑。
- 过滤器链(Filter Chain):管理多个过滤器,决定过滤器的执行顺序,并将请求传递给目标处理程序。
- 目标处理程序(Target):最终处理请求的组件,执行核心业务逻辑。
- 客户端(Client):发起请求的实体,通常是浏览器或其他用户代理。
工作原理
- 客户端发送请求,进入过滤器链。
- 过滤器链按顺序调用每个过滤器,执行预处理逻辑(如认证、日志)。
- 如果请求通过所有过滤器,过滤器链将请求传递给目标处理程序。
- 目标处理程序执行业务逻辑,生成响应。
- 响应可能再次经过过滤器链,执行后处理逻辑(如格式化、压缩)。
- 最终响应返回给客户端。
UML 类图
┌────────────────┐
│ Client │
├────────────────┤
│ │
└────────────────┘
↑
│
┌────────────────┐
│ FilterChain │
├────────────────┤
│ addFilter() │
│ doFilter() │
└────────────────┘
↑
│
┌────────────────┐ ┌────────────────┐
│ Filter │ │ Target │
├────────────────┤ ├────────────────┤
│ doFilter() │<----->│ execute() │
└────────────────┘ └────────────────┘
↑
│
┌────────────────┐
│ ConcreteFilter │
├────────────────┤
│ doFilter() │
└────────────────┘
代码示例(以 Java 为例)
以下是一个拦截过滤器模式的实现,模拟 Web 应用中的请求处理流程:
// 过滤器接口
interface Filter {
void doFilter(String request, FilterChain chain);
}
// 具体过滤器:认证过滤器
class AuthenticationFilter implements Filter {
@Override
public void doFilter(String request, FilterChain chain) {
System.out.println("认证过滤器: 检查用户身份 - " + request);
// 假设认证通过,继续下一个过滤器
chain.doFilter(request);
}
}
// 具体过滤器:日志过滤器
class LoggingFilter implements Filter {
@Override
public void doFilter(String request, FilterChain chain) {
System.out.println("日志过滤器: 记录请求 - " + request);
// 继续下一个过滤器
chain.doFilter(request);
}
}
// 过滤器链
class FilterChain {
private List<Filter> filters = new ArrayList<>();
private Target target;
private int currentFilter = 0;
public void addFilter(Filter filter) {
filters.add(filter);
}
public void setTarget(Target target) {
this.target = target;
}
public void doFilter(String request) {
if (currentFilter < filters.size()) {
Filter filter = filters.get(currentFilter);
currentFilter++;
filter.doFilter(request, this);
} else {
// 所有过滤器执行完毕,调用目标处理程序
target.execute(request);
}
}
}
// 目标处理程序
class Target {
public void execute(String request) {
System.out.println("目标处理程序: 处理请求 - " + request);
}
}
// 测试代码
public class Main {
public static void main(String[] args) {
// 创建过滤器链
FilterChain filterChain = new FilterChain();
// 添加过滤器
filterChain.addFilter(new AuthenticationFilter());
filterChain.addFilter(new LoggingFilter());
// 设置目标处理程序
filterChain.setTarget(new Target());
// 模拟客户端请求
System.out.println("处理请求 /home:");
filterChain.doFilter("/home");
System.out.println("\n处理请求 /user:");
filterChain.doFilter("/user");
}
}
输出:
处理请求 /home:
认证过滤器: 检查用户身份 - /home
日志过滤器: 记录请求 - /home
目标处理程序: 处理请求 - /home
处理请求 /user:
认证过滤器: 检查用户身份 - /user
日志过滤器: 记录请求 - /user
目标处理程序: 处理请求 - /user
拦截过滤器模式的特点
- 优点:
- 模块化:过滤器独立实现,易于添加、移除或修改,符合开闭原则。
- 灵活性:通过调整过滤器链的顺序或组合,可以动态改变处理逻辑。
- 可复用性:过滤器可复用于不同请求或应用场景。
- 解耦:将通用处理逻辑(如认证、日志)与业务逻辑分离。
- 缺点:
- 过滤器链过长可能影响性能,需优化过滤器逻辑。
- 过滤器之间的依赖关系可能导致复杂性增加。
- 如果过滤器设计不当,可能导致职责不清晰。
使用场景
- 需要对请求进行统一预处理或后处理的场景:
- Web 应用中的认证和授权(如登录验证)。
- 日志记录、性能监控、请求格式转换。
- 需要灵活组合处理逻辑的场景:
- Servlet 过滤器(如 Java EE 的
javax.servlet.Filter
)。 - Spring Security 的过滤器链。
- 需要分离通用逻辑与业务逻辑的场景:
- 请求压缩、加密、跨域处理(CORS)。
- 数据验证或清洗。
注意事项
- 与前端控制器模式的区别:
- 前端控制器模式关注请求的集中分发,处理路由和通用逻辑。
- 拦截过滤器模式关注请求的预处理或后处理,通常与前端控制器结合使用(如 Spring MVC 的过滤器与 DispatcherServlet)。
- 过滤器顺序:过滤器链的执行顺序对结果有影响,需合理配置。
- 短路机制:过滤器可中断请求处理(如认证失败直接返回),需明确定义终止条件。
- 性能优化:避免在过滤器中执行耗时操作,必要时可使用异步处理。
- 与责任链模式的相似性:拦截过滤器模式与责任链模式类似,但过滤器模式更专注于 Web 请求的拦截和处理,责任链模式更通用。
总结
拦截过滤器模式通过可插拔的过滤器链,为 Web 请求提供了灵活的预处理和后处理机制,广泛应用于认证、日志、数据转换等场景。它通过分离通用逻辑与业务逻辑,提高了系统的模块化和可维护性。设计时需注意过滤器的职责划分、执行顺序和性能优化,以确保系统的高效性和清晰性。