设计模式——责任链(结合Tomcat中Filter机制)
设计模式:责任链模式
说责任链之前,先引入一个场景,假如规定学生请假小于或等于 2 天,班主任可以批准;小于或等于 7 天,系主任可以批准;小于或等于 10 天,院长可以批准;其他情况不予批准;以此为需求,写一个程序,你会怎么做?按着过程思维方式,最快最直白的就是,if else嘛,配合java,无非多追加学生类和各个角色的类。下面介绍的设计模式或许会给我们一些启发。
责任链模式
责任链又叫做职责链,是属于行为型设计模式,它的初衷是为了解决一个事件需要经过多个对象处理是很常见的场景。责任链的运作流程是将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。
在责任链模式中,客户只需要将请求发送到责任链上即可,无须关心请求的处理细节和请求的传递过程,请求会自动进行传递。所以责任链将请求的发送者和请求的处理者解耦了。
责任链的实现
责任链的设计源于数据结构中的链表,从模式的定义中就能看出,它需要一串走下去,而每一个处理请求的对象,都需要记录下一个处理请求的对象,即标准的数据链表方式。

职责链模式的实现主要包含以下角色。
- 抽象处理者(Handler)角色:定义一个处理请求的接口,包含抽象处理方法和一个后继连接。
- 具体处理者(Concrete Handler)角色:实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
- 客户类(Client)角色:创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。
责任链模式的本质是解耦请求与处理,让请求在处理链中能进行传递与被处理;理解责任链模式应当理解其模式,而不是其具体实现。责任链模式的独到之处是将其节点处理者组合成了链式结构,并允许节点自身决定是否进行请求处理或转发,相当于让请求流动起来。
UML类图如下:

模式的实现例子:
参照以上的思想,我们针对一开始的场景编写请假的程序:
public class LeaveApprovalTest {
public static void main(String[] args) {
//组装责任链
Leader teacher1 = new ClassAdviser();
Leader teacher2 = new DepartmentHead();
Leader teacher3 = new Dean();
//Leader teacher4=new DeanOfStudies();
teacher1.setNext(teacher2);
teacher2.setNext(teacher3);
//teacher3.setNext(teacher4);
//提交请求
teacher1.handleRequest(8);
}
}
//抽象处理者:领导类
abstract class Leader {
private Leader next;
public void setNext(Leader next) {
this.next = next;
}
public Leader getNext() {
return next;
}
//处理请求的方法
public abstract void handleRequest(int LeaveDays);
}
//具体处理者1:班主任类
class ClassAdviser extends Leader {
public void handleRequest(int LeaveDays) {
if (LeaveDays <= 2) {
System.out.println("班主任批准您请假" + LeaveDays + "天。");
} else {
if (getNext() != null) {
getNext().handleRequest(LeaveDays);
} else {
System.out.println("请假天数太多,没有人批准该假条!");
}
}
}
}
//具体处理者2:系主任类
class DepartmentHead extends Leader {
public void handleRequest(int LeaveDays) {
if (LeaveDays <= 7) {
System.out.println("系主任批准您请假" + LeaveDays + "天。");
} else {
if (getNext() != null) {
getNext().handleRequest(LeaveDays);
} else {
System.out.println("请假天数太多,没有人批准该假条!");
}
}
}
}
//具体处理者3:院长类
class Dean extends Leader {
public void handleRequest(int LeaveDays) {
if (LeaveDays <= 10) {
System.out.println("院长批准您请假" + LeaveDays + "天。");
} else {
if (getNext() != null) {
getNext().handleRequest(LeaveDays);
} else {
System.out.println("请假天数太多,没有人批准该假条!");
}
}
}
}
//具体处理者4:教务处长类
class DeanOfStudies extends Leader {
public void handleRequest(int LeaveDays) {
if (LeaveDays <= 20) {
System.out.println("教务处长批准您请假" + LeaveDays + "天。");
} else {
if (getNext() != null) {
getNext().handleRequest(LeaveDays);
} else {
System.out.println("请假天数太多,没有人批准该假条!");
}
}
}
}
Tomcat中Filter的执行过程
前边已经讲述了关于责任链模式的结构与特点,下面介绍其应用场景,责任链模式通常在以下几种情况使用。
- 多个对象可以处理一个请求,但具体由哪个对象处理该请求在运行时自动确定。
- 可动态指定一组对象处理请求,或添加新的处理者。
- 需要在不明确指定请求处理者的情况下,向多个处理者中的一个提交请求。
说完了责任链的灵活应用,下面结合tomcat中Filter的例子,进行一个标准责任链的解析,先来看以下Tomcat的过滤器机制:

这是一个tomcat处理请求的过程,即它会有多个过滤器,这里的过滤器串联起来,形成一条过滤链,前端或者浏览器发来了request,会经过这条链,顺着链依次经过每个过滤器,最终由servlet处理后,再逐一返回。这有点像栈结构,但是这其中逐一处理,构成一条链,又符合责任链的设计规则。
查看一下Tomcat中Filter接口的源码:
public interface Filter {
void init(FilterConfig var1) throws ServletException;
//熟悉的doFilter(), 熟悉的3个参数request, reponse, filterChain.
void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;
void destroy();
}
下面是过滤链的接口源码:
public interface FilterChain {
void doFilter(ServletRequest var1, ServletResponse var2) throws IOException, ServletException;
}
具体的过滤链的实现,都会带有一个容器,来存放该链中的Filter,即过滤链中包含一个个的过滤器。
做一个简化版的过滤机制
下面我们简化模拟一下Tomcat处理Filter的过程,
首先定义简易版的request和response对象
public class Request{
String msg;
public void setMsg(String msg){
this.msg=msg;
}
}
public class Response{
public void deal(){
System.out.println();
}
}
定义Filter接口及两个实现(http校验,消息敏感字符校验)
public interface Filter{
void doFilter(Request req,Response rep,Filter filer);
}
public HttpFilter implements Filter{
void doFilter(Request req,Response rep,Filter filer){
System.out.println("处理了http验证"+req.getMsg());
filter.doFilter(req,rep,filter);
}
}
public SensitiveFilter implements Filter{
void doFilter(Request req,Response rep,Filter filer){
System.out.println("处理了敏感字符替换"+req.getMsg());
filter.doFilter(req,rep,filter);
}
}
定义过滤链:
public class FilterChain implements Filter{
List<Filter> filterlist = new Arrary<>();
private int index;
public FilterChain addFilter(Filter filter){
filterlist.add(filter);
return this;
}
void doFilter(Request req,Response res,Filter filter){
if(index == filterlist.size()){
return;//这里是逆序处理响应的关键, 当index为容器大小时, 证明对request的处理已经完成, 下面进入对response的处理.
}
Filter f = filterlist.get(index);//过滤器链按index的顺序拿到filter
index++;
f.doFilter(request, response, filter);
}
}
测试代码:
public class DemoBox {
public static void main(String[] args) {
String msg = "大家好 ";//以下三行模拟一个请求
Request request = new Request();
request.setMsg(msg);
Response response = new Response();//响应
FilterChain fc = new FilterChain();//过滤器链
HttpFilter f1 = new HttpFilter();//创建过滤器
SensitiveFilter f2 = new SensitiveFilter();//创建过滤器
fc.add(f1);//把过滤器添加到过滤器链中
fc.add(f2);
fc.doFilter(request, response, fc);//直接调用过滤器链的doFilter()方法进行处理
}
}
下面按着步骤,详细解释一下上面的代码:
- 首先我们分别创建一个
Request和Response对象.Request在传入进后端时需要依次被过滤器进行处理,Response对象在输出时要依次被过滤器处理. - 我们定义了一个Filter接口,它包含处理请求的方法doFilter,这里的Filter可以理解为责任链中的抽象处理者
- 依次实现了两个拦截器,HttpFilter,SensitiveFilter,做具体的过滤处理,可以理解为责任链中具体处理者的角色
- 实现一个Filter接口,做一个过滤链的类FilterChain,它除了基本的处理功能,还包含了一个过滤器容器FilterList,用它还存放整条链的Filter。
- 接着我们调用过滤器链的
doFilter()方法对request对象进行处理 - 这时过滤器链中的
index值为0, 通过index我们找到第一个过滤器并调用它的doFilter()方法 - 进入
doFilter()方法后, 首先会对request请求进行处理, 然后又调用了过滤器链的doFilter()方法. 这就是整个责任链模式的精妙之处, 它解释了为什么要给doFilter()加上一个过滤器链参数, 就是为了让每个过滤器可以调用过滤器链本身执行下一个过滤器。 - 为什么要调用过滤器链本身? 因为当调用过滤器本身后, 程序将跳转回到过滤器链的
doFilter方法执行, 这时index为1, 也就是拿到第二个过滤器, 然后继续处理。 - 正是由于这个跳转, 使得过滤器中对
response的处理暂时无法执行, 它必须等待上面的对过滤器链的方法返回才能被执行.
设计模式——责任链(结合Tomcat中Filter机制)的更多相关文章
- java 设计模式 -- 责任链模式
设计模式 – 责任链模式 介绍: 责任链模式是一种动态行为模式,有多个对象,每一个对象分别拥有其下家的引用.连起来形成一条链.待处理对象则传到此链上,在此链进行传递,且待处理对象并不知道此会被链上的哪 ...
- 浅谈Python设计模式 -- 责任链模式
声明:本系列文章主要参考<精通Python设计模式>一书,并且参考一些资料,结合自己的一些看法来总结而来. 之前在最开始就聊了Python设计模式有三种,其中关于创建型和结构型设计模式基本 ...
- iOS设计模式 - 责任链
iOS设计模式 - 责任链 原理图 说明 在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链.请求在这个链上传递,直到链上的某一个对象决定处理此请求.发出这个请求的客户端并不知道链 ...
- 【设计模式】Java设计模式 - 责任链模式
[设计模式]Java设计模式 - 责任链模式 不断学习才是王道 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 一个有梦有戏的人 @怒放吧德德 目录 [设计模式]Java设计模式 - 责 ...
- [工作中的设计模式]责任链模式chain
一.模式解析 责任链模式是一种对象的行为模式.在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链.请求在这个链上传递,直到链上的某一个对象决定处理此请求.发出这个请求的客户端并不知 ...
- php 23种设计模式 - 责任链模式
责任链模式 责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链.这种模式给予请求的类型,对请求的发送者和接收者进行解耦.这种类型的设计模式属于行 ...
- 设计模式-责任链模式Chain of Responsibility)
一.定义 职责链模式是一种对象的行为模式.在职责链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链.请求在这个链上传递,直到链上的某一个对象决定处理此请求.发出这个请求的客户端并不知道链 ...
- Java设计模式の责任链模式
在阎宏博士的<JAVA与模式>一书中开头是这样描述责任链(Chain of Responsibility)模式的: 责任链模式是一种对象的行为模式.在责任链模式里,很多对象由每一个对象对其 ...
- 设计模式——责任链(chain of responsibiltiy)
责任链模式在面向对象程式设计里是一种软件设计模式,它包含了一些命令对象和一系列的处理对象. 每一个处理对象决定它能处理哪些命令对象,它也知道如何将它不能处理的命令对象传递给该链中的下一个处理对象.也就 ...
随机推荐
- 牛客练习赛67 D牛妹爱数列 题解(dp)
题目链接 题目大意 给你一个长为n的01串,要你进行最少的操作使得这01串变成全为0,求最少操作次数 有两种不同类型的操作 1:翻转一个前缀 2:单调翻转一个元素 题目思路 居然是一个dp,标程讲的很 ...
- Java蓝桥杯02——第二题集锦:生日蜡烛、星期一、方格计数、猴子分香蕉
第二题 生日蜡烛(结果填空) 某君从某年开始每年都举办一次生日party,并且每次都要吹熄与年龄相同根数的蜡烛. 现在算起来,他一共吹熄了236根蜡烛. 请问,他从多少岁开始过生日party的? 请填 ...
- Arduion学习(一)点亮三色发光二极管
这是我接触Arduion以来第一个小实验 实验准备: 1.查阅相关资料,了解本次实验所用到的引脚.接口的相关知识. 2.准备Arduion板(本次实验所用到的型号为mega2560).三色发光二极管. ...
- mq网络请求命令设计&消息的批量发送
RemotingCommand: flag倒数第一位表示请求类型,0请求1返回.倒数第二位1.表示oneway 单条消息发送时,消息体的内容将保存在body种,批量消息发送,需要将多条消息体的内容存储 ...
- SpringBoot中JPA的学习
SpringBoot中JPA的学习 准备环境和项目配置 写一下学习JPA的过程,主要是结合之前SpringBoot + Vue的项目和网上的博客学习一下. 首先,需要配置一下maven文件,有这么两个 ...
- SQL,T-SQL简介
SQL: 结构化查询语言(Structured Query Language), 简称SQL,是一种特殊目的的编程语言,是一种数据库查询和程序设计语言,用于存取数据以及查询.更新和管理关系型数据库系 ...
- Spring Cloud 学习 (六) Spring Cloud Config
在实际开发过程中,每个服务都有大量的配置文件,例如数据库的配置.日志输出级别的配置等,而往往这些配置在不同的环境中也是不一样的.随着服务数量的增加,配置文件的管理也是一件非常复杂的事 在微服务架构中, ...
- Python之【模块】
双层装饰器 一个函数可以被多个装饰器装饰: 多层装饰器的本质是:嵌套: 执行规则是:解释自下而上,执行自上而下 •简单的用户权限验证程序: USE_INFO = {} # 初始化一个字典,用户存放用户 ...
- 编写测试用例 QQ账号6--10位自然数 某城市电话号码 126邮箱注册功能
- moviepy音视频剪辑:视频变换处理与内容相关的变换函数headblur、mask_and/or、mirror_x/y、rotate、painting、scroll介绍
一.引言 在<moviepy音视频剪辑:moviepy中的剪辑基类Clip详解>介绍了剪辑基类的fl.fl_time.fx方法,在<moviepy音视频剪辑:视频剪辑基类VideoC ...