Servlet Filter 原理分析与实战
Servlet Filter 使用责任链模式实现Filter的调度执行,通过FilterChain管理Filter的执行,实现了Filter之间的逻辑解耦。本文简化了Filter的扩展功能,可以清晰的看到责任链模式执行的骨架。
责任链模式
责任链目的:通过Chain封装调用链路,实现Filter解耦
Chain 里面维护了Filter集合,提供了Filter管理接口和调用下一个Filter的接口
class FilterChain {
// Filter 集合
List<Filter> filters = new ArrayList<>();
// 下一个 Filter 的下标
int idx;
/** 管理接口 add / update / remove */
public void addFilter(Filter filter) {
filters.add(filter);
}
/** 调用 下一个 Filter.doFilter */
public void doNextFilter() {
if (idx == filters.size()) {return;}
Filter filter = filters.get(idx++);
filter.doFilter(this);
}
}
Filter 只需要实现自己的逻辑,然后大喊 下一个 (chain.doNextFilter)
interface Filter {
void doFilter(FilterChain chain);
}
class LogFilter implements Filter {
@Override
public void doFilter(FilterChain chain) {
System.out.println(" log ------ start " );
// 调用 下一个
chain.doNextFilter();
System.out.println(" log ------ end " );
}
}
class AuthFilter implements Filter {
@Override
public void doFilter(FilterChain chain) {
System.out.println(" auth ------ start " );
// 调用 下一个
chain.doNextFilter();
System.out.println(" auth ------ end " );
}
}
责任链 核心 在于链的调度管理[Chain]
多个Filter 串行执行 形成调用链
Filter:单个Filter,实现自身的逻辑,调用下一个Filter
FilterChain:Filter链 维护一串Filters,提供下一个Filter的调用
实战
@Component
@Order(2)
public class TransactionFilter implements Filter {
@Autowired
private HttpServletReqUtil reqUtil;
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
final MyHttpServletRequestWrapper wrappedRequest = new MyHttpServletRequestWrapper(
(HttpServletRequest) request);
System.out.println("Inside Servlet Filter");
System.out.println("User IP address: " + reqUtil.getRemoteAddress(wrappedRequest));
System.out.println("Request Params: " + reqUtil.getRequestParams(wrappedRequest));
System.out.println("Request Payload: " + reqUtil.getPayLoad(wrappedRequest));
System.out.println("Exiting Servlet Filter");
chain.doFilter(wrappedRequest, response);
}
}
总结
- Filter通过责任链进行调用,由FilterChain统一管理调度,目的是解耦Filter
- Filter 适用场景:请求头Header处理/ IP防刷 / 敏感词过滤 / 资源访问控制
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。