设计模式之责任链模式,以tomcat中的过滤器为例

概述

由一组处理器依次处理某个数据,在处理过程中可能对数据进行修改。

详细

因为程序员相对的对Filter最熟悉,这里类图以filter为例。实际Spring下的Filter会比这个复杂的多,中间隔了很多GenericFilterBean、OncePerRequestFilter等类,这里是简化图

图中包含三类角色:
被处理的对象:request和response,被处理的对象可以是一个可以是多个,Filter中是这一对
过滤器链:负责如下事情

  • 存储所有需要执行的过滤器
  • 过滤器链的开始过滤
  • 通过遍历判断过滤器链是否执行完成

过滤器每次执行完后会返回到过滤器链,过滤器链判断有没有完成。过滤器可以选择不返回过滤器直接return的!

过滤器:负责处理请求和决定是否把请求还给流水线,流水线往下一个节点走。

举一个没有还给流水线的例子:
DefaultLogoutPageGeneratingFilter类

//省略了部分代码
public class DefaultLogoutPageGeneratingFilter extends OncePerRequestFilter {
	@Override
	protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {
		if (this.matcher.matches(request)) {
			// 走到这个分支的时候是不还的,直接返回了
			renderLogout(request, response);
		}
		else {
			if (logger.isTraceEnabled()) {
				logger.trace(LogMessage.format("Did not render default logout page since request did not match [%s]",
						this.matcher));
			}
			filterChain.doFilter(request, response);
		}
	}
}

时序图:
本时序图假设总共就3个过滤器,其中第二个过滤器的实现类有直接return的条件分支。
所以途中有两个分支,一个分支是继续遍历调用后面的过滤器
一个是直接return
FilterChain的doFilter的伪代码:

private Filter[] filters = 所有的过滤器。
public void doFilter(ServletRequest request,ServletResponse response){
	int n = 过滤器总数;
	int pos = 当前过滤器位置;
	if(pos<n){
	  filters[post++].doFilter(request, response);
	}
}

所以如果FilterChain的doFilter方法不被调用的话,他是不会继续执行下一个过滤器的,因此过滤器本身具备了停止执行后面过滤器的权限,他只要return就行。


版权声明:本文为a397525088原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。