Java设计模式-责任链模式(Chain of Responsibility Pattern)
目录
- 什么是责任链模式
- 责任链模式的实现方式
- Tomcat责任链模式的应用
为了避免请求发送者与多个请求处理者耦合在一起,于是将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。
一、什么是责任链模式
责任链模式会使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系,将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理他为止
在责任链模式中,客户只需要将请求发送到责任链上即可,无须关心请求的处理细节和请求的传递过程,请求会自动进行传递。所以责任链将请求的发送者和请求的处理者解耦了。
用一张图表示责任链模式
二、责任链模式的实现方式
模拟HTTP请求过程,在HTTP请求时经常对参数进行过滤,使用责任链模式实现多次过滤,代码如下
package org.ChainPattern.version1;
import java.util.ArrayList;
import java.util.List;
// 请求对象
class Request{
private String type;
private String msg;
public Request(String type,String msg){
this.type = type;
this.msg = msg;
}
public String getType() {
return this.type;
}
public String getMsg() {
return this.msg;
}
}
// 返回对象
class Response{
private String msg;
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
// 过滤器
interface Filter{
public void doFilter(Request request,Response response,Filter filter);
}
// HTTP过滤器
class HTTPFilter implements Filter{
@Override
public void doFilter(Request request, Response response, Filter filter) {
System.out.println("HTTPFilter开始处理请求数据..." + request.getMsg());
filter.doFilter(request,response,filter);
System.out.println("HTTPFilter开始处理返回数据...");
}
}
// 特殊字符过滤器
class SafeCheckFilter implements Filter{
@Override
public void doFilter(Request request, Response response, Filter filter) {
System.out.println("SafeCheckFilter开始处理请求数据..." + request.getMsg());
filter.doFilter(request,response,filter);
System.out.println("SafeCheckFilter开始处理返回数据...");
}
}
// 过滤器链
class FilterChain implements Filter{
// 要调用的所有的过滤器
List<Filter> filters = new ArrayList<>();
// 标识当前调用的过滤器下标
private int index;
// 添加过滤器
public void addFilter(Filter filter){
filters.add(filter);
}
// 执行过滤器
@Override
public void doFilter(Request request, Response response, Filter filter) {
// 如果过滤器没了,这是最后一个,那么返回
if (index == filters.size()){
// 设置返回数据,例如HTTP请求的数据库数据,或者登录状态等
response.setMsg("请求成功");
return;
}
// 获取过滤器
Filter f = filters.get(index);
index ++;
// 执行过滤器
f.doFilter(request,response,filter);
}
}
public class Test {
public static void main(String[] args) {
Request request = new Request("POST","POST请求");
Response response = new Response();
FilterChain chain = new FilterChain();
chain.addFilter(new HTTPFilter());
chain.addFilter(new SafeCheckFilter());
chain.doFilter(request,response,chain);
System.out.println("Response返回:" + response.getMsg());
}
}
// 执行结果
HTTPFilter开始处理请求数据...POST请求
SafeCheckFilter开始处理请求数据...POST请求
SafeCheckFilter开始处理返回数据...
HTTPFilter开始处理返回数据...
Response返回:请求成功
这就是责任链模式最关键的就是doFilter(Request request, Response response, Filter filter)
方法,传递的filter是FilterChain对象, 要记住永远是FilterChain对象,在FilterChain的doFilter方法中不断的get出Filter去执行,HTTPFilter、SafeCheckFilter的doFilter方法内部的filter.doFilter(request,response,filter);
的filter一直是FilterChain对象,自己调用doFilter并且把自己传进去,典型递归。
仔细看执行结果,是递归调用的样子,最开始的Filter会在最后返回。
HTTPFilter、SafeCheckFilter会分别处理Request、Response对象,每个Filter都有机会处理
三、Tomcat责任链模式的应用
前面我们举得例子其实就是模拟的Tomcat的HTTP请求过程,关键的类有
- ApplicationFilterChain:内部维护了所有需要调用的Filter
- FilterDispatcher、WsFilter等:实现了Filter的接口,负责处理不同的逻辑
ApplicationFilterChain的internalDoFilter会逐个取出filter进行调用,和我们上面的额例子一样也是用了 一个自增的索引pos,不断取出filter
再看下具体的Filter业务类:CsrfPreventionFilter.java,是不是和我们案例中写的代码非常类似
FilterDispatcher.java内容如下,可以看到FilterDispatcher负责调用Action
下图是一个tomcat处理请求的过程,即它会有多个过滤器,这里的过滤器串联起来,形成一条过滤链,前端或者浏览器发来了request,会经过这条链,顺着链依次经过每个过滤器,最终由servlet处理后,再逐一返回。这有点像栈结构,但是这其中逐一处理,构成一条链,又符合责任链的设计规则