简单实现–实现链式调用以及调用链中断

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) {
// 精髓,利用返回的boolean决定还是否往下传递
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;

/**
* @author deltaqin
* @date 2021/3/27 12:39 下午
*/
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
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 处理器完成处理。

1623034790443-1d0cd73e-d15a-4880-888d-0c4c29fe778a.png

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

1623034842803-d72f45e2-9694-44dd-a27d-90f88b336b15.png

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