简单实现–实现链式调用以及调用链中断
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| interface Filter { boolean doFilter(Msg m); }
class HTMLFilter implements Filter { @Override public boolean doFilter(Msg m) { String r = m.getMsg(); r = r.replace('<', '['); r = r.replace('>', ']'); m.setMsg(r); return true; } }
|
调用链也实现Filter接口,是为了可以两个链子连起来。也就是说把后面的链子当做过滤器的**List的最后一个元素。利用了多态,都实现了doFilter,但是具体的过滤器是具体的处理,FilterChain 的 doFilter是为了开始调用自己的链子。注意此时上一个还在栈里面,有点类似递归。**
- **add(Filter f) **返回 FilterChain ,是为了链式调用,注意add方法是只有FilterChain 有的,其他实现了Filter 的具体过滤器是没有这个方法的。
- doFilter(Msg m) :返回boolean 为了决定是否继续往下调用链子上面后面的调用器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class FilterChain implements Filter { private List<Filter> filters = new ArrayList<>();
public FilterChain add(Filter f) { filters.add(f); return this; }
public boolean doFilter(Msg m) { for(Filter f : filters) { if(!f.doFilter(m)) return false; }
return true; } }
|
调用案例
1 2 3 4 5 6 7 8 9 10
| FilterChain fc = new FilterChain(); fc.add(new HTMLFilter()).add(new SensitiveFilter());
FilterChain fc2 = new FilterChain(); fc2.add(new FaceFilter()).add(new URLFilter());
fc.add(fc2);
fc.doFilter(msg);
|
Servlet的Filter
和上面直接在FilterChain里面遍历所有的Filter,调用doFilter不一样,为了实现req是abc顺序,resp是cba顺序,这里使用利用了递归的思想,不在FilterChain设置for循环,而是**每一个具体的Filter都去调用FilterChain的doFilter,让FilterChain去调用下一个Filter,返回的时候其实就是递归返回,再执行后面的语句,也就是对resp操作,就相当于是栈**,毕竟栈就是递归的具象。所以返回的时候顺序就反过来了。
- **具体的过滤器**的doFilter实现:
<font style="color:#cc7832;">public boolean </font>``<font style="color:#ffc66d;">doFilter</font>``_(_``Request request``<font style="color:#cc7832;">, </font>``Response response``<font style="color:#cc7832;">, </font>``FilterChain chain``_)_
- **内部自己处理之后调用Filter的doFilter方法来调用下一个filter **
- **FilterChain**的doFilter实现:
public void doFilter(Request request, Response response)
- 内部直接调用链子里的下一个Filter
- 借助对象变量 index 标志当前运行到哪一个过滤器了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
| package com.deltaqin.designPattern.d10_chainOfResponsibility.servletFilter;
import java.util.ArrayList; import java.util.List;
public class ServletFilter { public static void main(String[] args) { Request request = new Request(); request.str = "大家好:),<script>,deltaqin ,大家都是996 "; Response response = new Response(); response.str = "response";
FilterChain chain = new FilterChain(); chain.add(new HTMLFilter()).add(new SensitiveFilter()); chain.doFilter(request, response); System.out.println(request.str); System.out.println(response.str);
} }
interface Filter { void doFilter(Request request, Response response, FilterChain chain); }
class HTMLFilter implements Filter { @Override public void doFilter(Request request, Response response, FilterChain chain) { request.str = request.str.replaceAll("<", "[").replaceAll(">", "]") + "HTMLFilter()"; chain.doFilter(request, response); response.str += "--HTMLFilter()";
} }
class Request { String str; }
class Response { String str; }
class SensitiveFilter implements Filter { @Override public void doFilter(Request request, Response response, FilterChain chain) { request.str = request.str.replaceAll("996", "955") + " SensitiveFilter()"; chain.doFilter(request, response); response.str += "--SensitiveFilter()";
} }
class FilterChain { List<Filter> filters = new ArrayList<>(); int index = 0;
public FilterChain add(Filter f) { filters.add(f); return this; }
public void doFilter(Request request, Response response) { if(index == filters.size()) return;
Filter f = filters.get(index++); f.doFilter(request, response, this); } }
|
Tomcat中的责任链模式
简单的上一个链条调用下一个链条
HTTP 协议可简单分为请求头和请求体两部分,Tomcat 在收到一条完整的 HTTP 请求时,也会将其分为请求头和请求体两部分进行处理的。
不过在真正的 Tomcat 实现中,会将 HTTP 请求细分为更多部分,然后逐步进行处理,整个 Tomcat 代码处理 HTTP 请求的实现也更为复杂。
试想一下,Tomcat 将处理请求的各个细节的实现代码都堆到一个类中,那这个类的代码会非常长,维护起来也非常痛苦,可以说是“牵一发而动全身”。如果 HTTP 请求升级,那就需要修改这个臃肿的类,显然是不符合“开放-封闭”原则的。
为了实现像 HTTP 这种多部分构成的协议的处理逻辑,我们可以**使用责任链模式来划分协议中各个部分的处理逻辑,将那些臃肿实现类拆分成多个 Handler(或 Interceptor)处理器,在每个 Handler(或 Interceptor)处理器中只专注于 HTTP 协议中一部分数据的处理。我们可以开发多个 Handler 处理器,然后按照业务需求将多个 Handler 对象组合成一个链条,从而实现整个 HTTP 请求的处理。**
这样做既可以将复杂、臃肿的逻辑拆分,便于维护,又能将不同的 Handler 处理器分配给不同的程序员开发,提高开发效率。
在责任链模式中,Handler 处理器会持有对下一个 Handler 处理器的引用,也就是说当一个 Handler 处理器完成对关注部分的处理之后,会将请求通过这个引用传递给下一个 Handler 处理器,如此往复,直到整个责任链中全部的 Handler 处理器完成处理。

假设我们自定义了一套协议,其请求中包含 A、B、C 三个核心部分,业务系统使用 Handler A、Handler B、Handler C 三个处理器来处理这三部分的数据。如果业务变化导致我们的自定义协议也发生了变化,协议中的数据变成了 A、C、D 这三部分,那么我们只需要动态调整构成责任链的 Handler 处理器即可,最新的责任链变为 Handler A、Handler C、Handler D。如下图所示:

由此可见,责任链模式可以帮助我们复用 Handler 处理器的实现逻辑,提高系统的可维护性和灵活性,很好地符合了“开放-封闭”原则。