设计模式学习笔记(十四)责任链模式实现以及在Filter中的应用
责任链模式(Chain Of Responsibility Design Pattern),也叫做职责链,是将请求的发送和接收解耦,让多个接收对象都有机会处理这个请求。当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。

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

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 为例:

所以当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 框架来实现,借一张来自《设计模式之美》的图片来说明:

客户端发送请求,首先会经过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 {
}
}
会有各种具体处理类的实现:

此外在其他框架中也存在着职责链模式的使用,比如Dubbo Filter、Netty ChannelPipeline等等
三、责任链模式实战
模拟在618大促期间的业务系统上线审批流程场景:
像是这些⼀线电商类的互联⽹公司,阿⾥、京东、拼多多等,在618期间都会做⼀些运营活动场景以及 提供的扩容备战,就像过年期间百度的红包⼀样。但是所有开发的这些系统都需要陆续的上线,因为临 近618有时候也有⼀些紧急的调整的需要上线,但为了保障线上系统的稳定性是尽可能的减少上线的, 也会相应的增强审批⼒度。就像⼀级响应、⼆级响应⼀样。
⽽这审批的过程在随着特定时间点会增加不同级别的负责⼈加⼊,每个⼈就像责任链模式中的每⼀个核 ⼼点。对于研发并不需要关⼼具体的审批流程处理细节,只需要知道这个上线更严格,级别也更 ⾼,但对于研发⼈员来说同样是点击相同的提审按钮,等待审核。
使用责任链模式可以将各个服务模块按照一、二、三级进行分离,每个级别可以像Filter一样用Successor下一个级别的方法进行调用。具体结构图如下(来自《重学Java设计模式》)

具体代码如下:
参考资料
《设计模式之美》
http://c.biancheng.net/view/4024.html
《重学Java设计模式》
设计模式学习笔记(十四)责任链模式实现以及在Filter中的应用的更多相关文章
- C#设计模式学习笔记:(20)职责链模式
本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/8109100.html,记录一下学习过程以备后续查用. 一.引言 今天我们要讲行为型设计模式的第八个模式--职 ...
- 设计模式之二十:责任链模式(Chain of Responsibility)
感觉这个设计模式和组合模式一样是一种非常巧妙的设计模式,在须要使用它的地方假设不使用这样的设计模式代码会变的非常复杂,可是这样的设计模式的基本原理又是非常easy的. 责任链模式: 通过使多个对象都有 ...
- javascript设计模式学习之十四——中介者模式
一.中介者模式的定义和应用场景 中介者模式的作用在于解除对象之间的紧耦合关系,增加一个中介者之后,所有对象都通过中介者来通信,而不是互相引用,当一个对象发生变化的时候,仅需要通知中介者即可.从而将网状 ...
- Java 设计模式系列(十四)命令模式(Command)
Java 设计模式系列(十四)命令模式(Command) 命令模式把一个请求或者操作封装到一个对象中.命令模式允许系统使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复 ...
- python3.4学习笔记(十四) 网络爬虫实例代码,抓取新浪爱彩双色球开奖数据实例
python3.4学习笔记(十四) 网络爬虫实例代码,抓取新浪爱彩双色球开奖数据实例 新浪爱彩双色球开奖数据URL:http://zst.aicai.com/ssq/openInfo/ 最终输出结果格 ...
- 设计模式(13)--Chain of Responsibility(责任链模式)--行为型
作者QQ:1095737364 QQ群:123300273 欢迎加入! 1.模式定义: 责任链模式是一种对象的行为模式.在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一 ...
- java23种设计模式之十:责任链模式
最近在学习netty中发现其中用到了责任链模式,然后结合自己在写代码中遇到了大量写if...else的情况,决定学习一下责任链模式. 一.什么样的场景下会选择用责任链模式 我们在进行业务逻辑判断时,需 ...
- Java设计模式十九——责任链模式
责任链模式 老李的苦恼 每个人在出生的时候,都早已在暗中被标好了三六九等. 老李是一名建筑工地的木匠,和大多数生活在社会最底层的农民工一样,一辈子老实本分,胆小怕事.在他们的心中,谁当老爷都没有区别, ...
- C#设计模式学习笔记:(3)抽象工厂模式
本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/7596897.html,记录一下学习过程以备后续查用. 一.引言 接上一篇C#设计模式学习笔记:简单工厂模式( ...
随机推荐
- think php jq ajax删除
表单展示页面 <!doctype html> <html lang="en"> <head> <meta charset="UT ...
- laravel 框架简易增删改查
参看网址:http://www.yan.com/mou/add 图书增加HTML页面 //图书增加路由 Route::get('mou/add','MouController@store'); //控 ...
- VBS文件无限循环解决办法
VBS文件无限循环解决办法,也就相当于编程中的停止运行指令. 那么如何关掉VBS文件呢?当然关机后会自动关掉,还有另外一种方法就是,在"任务管理器"中找到进程"WScri ...
- libx264开发笔记(一):libx264介绍、海思平台移植编译
前言 在编译ffmpeg时,使用到h264编码时是需要依赖libx264的,本文章是将将libx264作为静态库移植到海思上. 相关博客 <Qt开发笔记之编码x264码流并封装mp4(一 ...
- 阿里云服务器搭建vulhub靶场
阿里云服务器搭建vulhub靶场 环境 服务器:阿里云服务器 系统:centos7 应用:vulhub 步骤 vulhub需要依赖docker搭建,首先安装docker. 使用以下方法之一: # cu ...
- TypeScript 初体验
TypeScript学习 1 安装环境 a 首先安装node.js node.js 用来将ts文件解析成js文件 供浏览器使用: 解析ts文件 tsc filename.ts b. 使用npm (no ...
- MySQL数据库阶段学习目录
MySQL数据库学习目录 MySQL数据库初识 MySQL的库表详细操作 MySQL行(记录)的详细操作 快捷使用数据库.表.表内容增删改查 MySQL之单表查询 MySQL之多表查询 Navicat ...
- 后门及持久化访问3----进程注入之AppInit_DLLs注册表项
进程注入之AppInit_DLLs注册表项 User32.dll被加载到进程时,会获取AppInit_DLLs注册表项,若有值,则调用LoadLibrary() API加载用户DLL.只会影响加载了u ...
- 74CMS 3.4 反射型XSS漏洞
一. 启动环境 1.双击运行桌面phpstudy.exe软件 2.点击启动按钮,启动服务器环境 二.代码审计 1.双击启动桌面Seay源代码审计系统软件 2.因为74CMS3.4源代码编辑使用GBK编 ...
- 一个最简单的Dubbo入门框架
Dubbo背景和简介 Dubbo开始于电商系统,因此在这里先从电商系统的演变讲起. 1.单一应用框架(ORM) 当网站流量很小时,只需一个应用,将所有功能如下单支付等都部署在一起,以减少部署节点和成本 ...
