1

设计模式学习笔记(十四)责任链模式实现以及在Filter中的应用 - 归斯君

 2 years ago
source link: https://www.cnblogs.com/EthanWong/p/16101006.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

责任链模式(Chain Of Responsibility Design Pattern),也叫做职责链,是将请求的发送和接收解耦,让多个接收对象都有机会处理这个请求。当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。

责任链模式

一、责任链模式介绍#

其实在日常生活中,有不少使用责任链的场景。比如公司采购审批流程,需要各个部门领导的批准同意。在责任链模式中,客户端只需要将请求发送到责任链上,无须关心请求的处理细节和传递,请求会自动进行传递。

1.1 责任链模式的结构#

责任链模式的结构大致如下所示:

image-20220404203259612

  • abstract Handler:抽象处理者,定义一个处理请求的接口,内部包含抽象处理方法和后继具体处理者
  • Handler1、Handler2:具体处理者,具体实现抽象处理者的方法,并对请求做一些逻辑处理
  • Client:客户端,使用职责链模式

1.2 责任链模式的实现#

根据上面的类图,可以实现如下代码:

/**
 * @description: 抽象处理类
 * @author: wjw
 * @date: 2022/4/4
 */
public abstract class Handler {

    private Handler successor;

    public Handler getSuccessor() {
        return successor;
    }

    public void setSuccessor(Handler successor) {
        this.successor = successor;
    }

    /**
     * 处理请求的抽象方法
     * @param request 请求
     */
    public abstract void handleRequest(String request);
}
/**
 * @description: 具体处理者1
 * @author: wjw
 * @date: 2022/4/4
 */
public class Handler1 extends Handler{

    private String handler;

    public Handler1(String handler) {
        this.handler = handler;
    }

    @Override
    public void handleRequest(String request) {
        if ("handler1".equals(request)) {
            System.out.println("具体处理者handler1进行请求处理");
        } else {
            if (getSuccessor() != null) {
                //如果指向下一个具体处理者
                getSuccessor().handleRequest(request);
            } else {
                System.out.println("没有处理者进行处理");
            }
        }
    }
}
/**
 * @description: 具体处理者2
 * @author: wjw
 * @date: 2022/4/4
 */
public class Handler2 extends Handler{

    private String handler;

    public Handler2(String handler) {
        this.handler = handler;
    }

    @Override
    public void handleRequest(String request) {
        if ("handler2".equals(request)) {
            System.out.println("具体处理者handler2进行请求处理");
        } else {
            if (getSuccessor() != null) {
                getSuccessor().handleRequest(request);
            } else {
                System.out.println("请求没有被任何处理者处理");
            }
        }
    }
}
/**
 * @description: 客户端类
 * @author: wjw
 * @date: 2022/4/4
 */
public class Client {
    public static void main(String[] args) {
        Handler handler1 = new Handler1("handler1");
        Handler handler2 = new Handler2("handler2");
        handler1.setSuccessor(handler2);
        handler1.handleRequest("handler1");
        handler1.handleRequest("handler2");

    }
}

测试结果:

具体处理者handler1进行请求处理
具体处理者handler2进行请求处理

二、责任链模式的应用场景#

职责链模式最常见的应用就是用来开发各种框架的过滤器和拦截器,比如Spring Interceptor和Servlet Filter

2.1 在Servlet Filter中的应用#

Filter 可以实现对HTTP 请求的过滤功能,比如鉴权、限流、记录日志、验证参数等等。比如一些Servlet 容器(TomCat、Jetty等)就支持Filter的过滤功能。以TomCat 为例:

image-20220404214532930

所以当Servlet 请求到来时,首先会经过Filter 处理,最后再到达Servlet实例。我这里选取的TomCat版本是SpringBoot自带的9.0,先来看看FilterChain 的接口:

public interface FilterChain {
    //Filter具体实现
    void doFilter(ServletRequest var1, ServletResponse var2) throws IOException, ServletException;
}

ApplicationFilterChain是责任链模式的具体实现类:

public final class ApplicationFilterChain implements FilterChain {
    private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0]; //Filter配置数组
    private int pos = 0; //执行Filter的序号
    private int n = 0;	 //目前Filter的个数
    private Servlet servlet = null;

    public ApplicationFilterChain() {
    }
    
	@Override
    public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
        //Filter 具体实现
        //...
    }
    
    public static ServletRequest getLastServicedRequest() {
        return (ServletRequest)lastServicedRequest.get();
    }

    public static ServletResponse getLastServicedResponse() {
        return (ServletResponse)lastServicedResponse.get();
    }

    void addFilter(ApplicationFilterConfig filterConfig) {
        ApplicationFilterConfig[] newFilters = this.filters;
        int var3 = newFilters.length;

        for(int var4 = 0; var4 < var3; ++var4) {
            ApplicationFilterConfig filter = newFilters[var4];
            if (filter == filterConfig) {
                return;
            }
        }
		//增加Filter
        if (this.n == this.filters.length) {
            newFilters = new ApplicationFilterConfig[this.n + 10];
            System.arraycopy(this.filters, 0, newFilters, 0, this.n);
            this.filters = newFilters;
        }

        this.filters[this.n++] = filterConfig;
    }
}

2.2 在Spring Interceptor中的应用#

和Servlet Filter类似,在Spring 中也有对应的过滤器 Interceptor。它是由Spring MVC 框架来实现,借一张来自《设计模式之美》的图片来说明:

image-20220404221601450

客户端发送请求,首先会经过Servlet Filter,然后再经过Spring Interceptor,最后再到达具体的业务中。

和Filter一样,Interceptor 中也是基于责任链模式来实现的,与之相对的HandlerInterceptor是抽象处理接口:

public interface HandlerInterceptor {
    default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return true;
    }

    default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
    }

    default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
    }
}

会有各种具体处理类的实现:

image-20220404222327991

此外在其他框架中也存在着职责链模式的使用,比如Dubbo Filter、Netty ChannelPipeline等等

三、责任链模式实战#

模拟在618大促期间的业务系统上线审批流程场景:

像是这些⼀线电商类的互联⽹公司,阿⾥、京东、拼多多等,在618期间都会做⼀些运营活动场景以及 提供的扩容备战,就像过年期间百度的红包⼀样。但是所有开发的这些系统都需要陆续的上线,因为临 近618有时候也有⼀些紧急的调整的需要上线,但为了保障线上系统的稳定性是尽可能的减少上线的, 也会相应的增强审批⼒度。就像⼀级响应、⼆级响应⼀样。

⽽这审批的过程在随着特定时间点会增加不同级别的负责⼈加⼊,每个⼈就像责任链模式中的每⼀个核 ⼼点。对于研发并不需要关⼼具体的审批流程处理细节,只需要知道这个上线更严格,级别也更 ⾼,但对于研发⼈员来说同样是点击相同的提审按钮,等待审核。

image-20220404223156189

使用责任链模式可以将各个服务模块按照一、二、三级进行分离,每个级别可以像Filter一样用Successor下一个级别的方法进行调用。具体结构图如下(来自《重学Java设计模式》)

image-20220404223642273

具体代码如下:

参考资料#

《设计模式之美》

http://c.biancheng.net/view/4024.html

《重学Java设计模式》


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK