利用责任链模式设计一个拦截器

名为责任链或者拦截器或者过滤器的简单模拟 看到strut2的Interceptor(拦截器), tomcat源码的Valve(tomcat中各种各样容器如Wrapper,Context都是靠Valve实现各种功能), 以及最早学习到的java web中的javax.servlet.Filter的概念, 都是一种链式的处理流程,这一个环节处理完成,然后处理另一个环节,这样就可以在一个处理本身的之前和之后做一些事情了。 比如说,struts2中Action在执行之前会首先执行一些Interceptor,完成诸如权限验证/属性注入/Validation/国际化等等的功能, 我看过一个比较好的功能是,利用strut2的拦截器和*-Validation.xml文件以及标签(strut2标签,主要是form-close.ftl这个模板文件),自动生成页面的Form前端验证。(当然辅助的客户端js文件如jquery/jquery-validation也是需要的)。 以上的这些功能,通过一种名为责任链或者拦截器或者过滤器(语义上的区别而技术上没有什么区别,知道做了什么就行了)的设计模式可以实现,那么就来看看什么是责任链的设计模式。 以下内容参考北京尚学堂的马士兵老师的设计模式视频,在此感谢。 立即下载

前言

近期在做Cicada的拦截器功能,正好用到了责任链模式。

这个设计模式在日常使用中频率还是挺高的,借此机会来分析分析。

责任链模式

先来看看什么是责任链模式。

引用一段维基百科对其的解释:

责任链模式在面向对象程式设计里是一种软件设计模式,它包含了一些命令对象和一系列的处理对象。每一个处理对象决定它能处理哪些命令对象,它也知道如何将它不能处理的命令对象传递给该链中的下一个处理对象。该模式还描述了往该处理链的末尾添加新的处理对象的方法。

光看这段描述可能大家会觉得懵,简单来说就是该设计模式用于对某个对象或者请求进行一系列的处理,这些处理逻辑正好组成一个链条。

下面来简单演示使用与不使用责任链模式有什么区别和优势。

责任链模式的应用

传统实现

假设这样的场景:传入了一段内容,需要对这段文本进行加工;比如过滤敏感词、错别字修改、最后署上版权等操作。

常见的写法如下:

publicclassMain{    publicstaticvoidmain(String[] args) {Stringmsg ="内容内容内容";Stringresult = Process.sensitiveWord()                .typo()                .copyright();    }}

这样看似没啥问题也能解决需求,但如果我还需要为为内容加上一个统一的标题呢?在现有的方式下就不得不新增处理方法,并且是在这个客户端(Process)的基础上进行新增。

显然这样的扩展性不好。

责任链模式实现

这时候就到了责任链模式发挥作用了。

该需求非常的符合对某一个对象、请求进行一系列处理的特征。

于是我们将代码修改:

这时Process就是一个接口了,用于定义真正的处理函数。

publicinterfaceProcess{/**    * 执行处理    *@parammsg    */voiddoProcess(String msg);}

同时之前对内容的各种处理只需要实现该接口即可:

publicclassSensitiveWordProcessimplementsProcess{@OverridepublicvoiddoProcess(String msg){        System.out.println(msg +"敏感词处理");    }}publicclassCopyrightProcessimplementsProcess{@OverridepublicvoiddoProcess(String msg){        System.out.println(msg +"版权处理");    }}publicclassCopyrightProcessimplementsProcess{@OverridepublicvoiddoProcess(String msg){        System.out.println(msg +"版权处理");    }}

然后只需要给客户端提供一个执行入口以及添加责任链的入口即可:

publicclassMsgProcessChain{privateList chains =newArrayList<>() ;/**    * 添加责任链    *@paramprocess    *@return*/publicMsgProcessChainaddChain(Process process){        chains.add(process) ;returnthis;    }/**    * 执行处理    *@parammsg    */publicvoidprocess(String msg){for(Process chain : chains) {            chain.doProcess(msg);        }    }}

这样使用起来就非常简单:

publicclassMain{publicstaticvoidmain(String[] args){        String msg ="内容内容内容==";        MsgProcessChain chain =newMsgProcessChain()                .addChain(newSensitiveWordProcess())                .addChain(newTypoProcess())                .addChain(newCopyrightProcess()) ;        chain.process(msg) ;    }}

当我需要再增加一个处理逻辑时只需要添加一个处理单元即可(addChain(Process process)),并对客户端chain.process(msg)是无感知的,不需要做任何的改动。

可能大家没有直接写过责任链模式的相关代码,但不经意间使用到的却不少。

比如Netty中的pipeline就是一个典型的责任链模式,它可以让一个请求在整个管道中进行流转。

通过官方图就可以非常清楚的看出是一个责任链模式:

用责任链模式设计一个拦截器

对于拦截器来说使用责任链模式再好不过了。

下面来看看在Cicada中的实现:

首先是定义了和上文Process接口类似的CicadaInterceptor抽象类:

publicabstractclassCicadaInterceptor{publicbooleanbefore(CicadaContext context,Param param)throwsException{returntrue;    }publicvoidafter(CicadaContext context,Param param)throwsException{}}

同时定义了一个InterceptProcess的客户端:

其中的loadInterceptors()会将所有的拦截器加入到责任链中。

再提供了两个函数分别对应了拦截前和拦截后的入口:

实际应用

现在来看看具体是怎么使用的吧。

在请求的handle中首先进行加载(loadInterceptors(AppConfig appConfig)),也就是初始化责任链。

接下来则是客户端的入口;调用拦截前后的入口方法即可。

由于是拦截器,那么在before函数中是可以对请求进行拦截的。只要返回false就不会继续向后处理。所以这里做了一个返回值的判断。

同时对于使用者来说只需要创建拦截器类继承CicadaInterceptor类即可。

这里做了一个演示,分别有两个拦截器:

记录一个业务handle的执行时间。

在after里打印了请求参数。

同时可在第一个拦截器中返回false让请求被拦截。

先来做前两个试验:

这样当我请求其中一个接口时会将刚才的日志打印出来:

接下来我让打印执行时间的拦截器中拦截请求,同时输入向前端输入一段文本:

请求接口可以看到如下内容:

同时后面的请求参数也没有打印出来,说明请求确实被拦截下来。

同时我也可以调整拦截顺序,只需要在@Interceptor(order = 1)注解中定义这个order属性即可(默认值是 0,越小越先执行)。

之前是打印请求参数的拦截器先执行,这次我手动将它的 order 调整为 2,而打印时间的 order 为 1 。

再次请求接口观察后台日志:

发现打印执行时间的拦截器先执行。

那这个执行执行顺序如何实现自定义配置的呢?

其实也比较简单,有以下几步:

在加载拦截器时将注解里的order保存起来。

设置拦截器到责任链中时通过反射将order的值保存到各个拦截器中。

最终通过排序重新排列这个责任链的顺序。

贴一些核心代码。

扫描拦截器时保存order值:

保存order值到拦截器中:

重新对责任链排序:

欢迎工作一到八年的Java工程师朋友们加入Java高级交流群:854630135

本群提供免费的学习指导 架构资料 以及免费的解答

不懂得问题都可以在本群提出来 之后还会有直播平台和讲师直接交流噢

哦对了,喜欢就别忘了关注一下哦~

责任连模式示例代码,模仿拦截器的实现 责任链模式是一种设计模式。在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。 立即下载

相关推荐

Python脚本自动化芯片设计?PyAether实战教程带你玩转EDA

本文通过PyAether实战教程,详细介绍了如何利用Python脚本实现芯片设计自动化。内容涵盖环境搭建、核心对象模型解析,并重点演示了原理图自动生成、参数化单元创建及设计验证流程集成,帮助EDA工程师从重复性手动操作中解放,显著提升设计效率与一致性。

e4f5g6h的博客 1319

Java设计模式之责任链模式(简单易懂)

前言: 责任链模式(Chain of Responsibility): 使多个对象都有机会处理同一请求,从而避免请求的发送者和接受者之间的耦合关系,每个对象都是一个处理节点,将这些对象连成一条链,并沿着这条链传递该请求。 网上有很多朋友已经对该模式介绍的非常详细了,也有案例帮助理解,可参考 Java设计模式之职责链模式 一篇文章搞懂Java设计模式之责任链模式_lzy_tinyjoy-优快云博客_java责任链模式 ...

小天狼星的博客 2万+

PTA-浙大版 《Python程序设计》 第三章编程题目及答案

博主第一次写优快云的博客,所以排版上可能有些不尽人意,代码部分均为自己的思路,可能复杂或者考虑欠妥,欢迎大家一起讨论~ 第一题:大于身高的平均值 这里用了np数组求得平均数,当然for循环累加也是可以的 import numpy as np data = input().split() data = list(map(int,data)) avg = np.mean(data) for i in data: if i > avg: print(i,end = '

Legendwqs的博客 1万+

设计模式——责任链

OA系统的采购审批项目、职责链模式基本介绍、职责链模式解决 OA 系统采购审批项目

种一棵树最好的时间是十年前,其次是现在 3803

5G 网络的移动性管理上下文对比介绍

5G 网络的移动性管理上下文对比介绍 4G/5G MM移动性管理机制对比 5G引入了新移动性管理状态,通过mobility pattern(移动方式)实现按需的移动性管理等。 MM的相关状态分为一下几种: RM状态(用户注册管理 注册态/非注册态)和CM状态(用户连接态/空闲态)独立;RM状态标识UE是否注册到网络,CM状态标识UE和核心网的信令连接是否存在。 RAN侧引入RRC-inactive state:UE(用户端)对于CN(核心网)而言处于连接态,对RAN(接入网)而言处于Ld..

m0_59032675的博客 4827

ThingsBoard入门实战(二):ThingsBoard 设备接入

文章目录ThingsBoard 设备接入一、设备配置/设备类型二、设备三、设备接入HTTPCOAPMQTT四、下一步 ThingsBoard 设备接入 设备接入并不一定需要真正的设备,我们可以通过程序。或者命令来模拟设备,向平台发送信息。 这节我们先为用户分配一个设备,然后通过模拟设备命令更新设备的状态(遥测值)。 一、设备配置/设备类型 添加一个叫"路灯"的设备配置。 设备配置听起来比较抽象,可以认为是设备类型或者是设备类型的配置。实际上,ThingsBoard 中很多时候让选择设备类型,就是选的这个。

AIGC搞起 1万+

Java描述设计模式(15):责任链模式

将请求和处理逻辑分开,实现解耦提高系统的灵活性;当责任链过长时,性能会下降,测试也会变得复杂;应用场景请假、加薪、费用等常见的审批流程;ENDhttpshttps。

【积累】,是一个长期持续的过程。 994

SAP PP模块 MRP配置实战:5步完成工厂级物料需求计划激活

本文详细介绍了SAP PP模块中物料需求计划(MRP)的工厂级配置实战,通过5个关键步骤从基础环境准备到最终激活。内容涵盖SPRO后台配置、MRP控制者定义、主数据设置及核心参数调整,帮助顾问快速掌握MRP配置清单的完整流程,确保物料需求计划的高效运行。

weixin_30431445的博客 344

用责任链模式设计拦截器

我在 Redant(https://github.com/all4you/redant) 中通过继承 ChannelHandler 实现了拦截器的功能,并且 pipeline 就是一种责任链模式的应用。但是后来我对原本的拦截器进行了重新设计,为什么这样做呢,因为原本的方式是在 ChannelH...

chizhihe8199的博客 263

Isaac Gym环境安装和四足机器人模型的训练

该方法提出一种训练模式,该模式通过在单个GPU工作站上使用大规模并行的方法来实现现实世界机器人任务的快速控制策略的生成。

weixin_44061195的博客 3万+

Vue - 简约大气 404 页面

效果图 实现代码 复制即可。 <template> <div> <div class="error"> <!-- 图片可保存到本地 --> <img src="https://img-blog.csdnimg.cn/20210715111039922.png"> <p>抱歉!你访问的页面不存在或已删除 :( </p> <span class="back" @click="go(

🏆 前端领域优质创作者 3371

java设计模式---责任链模式详解

深入理解责任链模式

zhenghuishengq的博客 2万+

Python与CAD系列基础篇(二)创建点和直线并修改样式

①通过pyautocad连接AutoCAD进行处理②通过ezdxf处理dxf格式文件。创建和编辑点和直线的方法,并演示如何修改它们的样式、颜色和线型。

weixin_43894929的博客 3036

OkHttp框架中拦截器设计精髓之责任链模式

OkHttp框架中拦截器设计精髓之责任链模式

qq_15274383的博客 2654

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

Android自定义拦截器模式,Okhttp3源码解析(4)-拦截器与设计模式

前言上节我们讲了okhttp的整体的流程,里面的核心方法之一是getResponseWithInterceptorChain() ,这个方法应该知道吧?通过拦截器层层处理返回Response;这个方法中其实应用了责任链设计模式。今天主要讲一下它是如何应用的!责任链设计模式责任链模式的定义在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对...

weixin_26872803的博客 379

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

Spring MVC拦截器中的责任链模式深度解析

深度剖析责任链

m0_61715294的博客 1479

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

责任链模式原理详解和源码实例以及Spring AOP拦截器链的执行源码如何使用责任链模式?

自定义拦截器示例@OverrideSystem.out.println("方法调用前: " + invocation.getMethod().getName());// 继续链System.out.println("方法调用后: " + invocation.getMethod().getName());责任链模式核心:解耦请求发送者与处理者,允许多个对象按链式处理请求。Spring AOP 实现:通过管理拦截器链,每个按责任链模式依次执行。优势:灵活扩展、职责分离、动态流程控制。应用场景。

qq_39126115的博客 1540

OKHttp拦截器之责任链模式

OKHttp中一个比较有意思的地方就是提供了拦截器机制 说起这个拦截器,它使用了一个比较冷门的设计模式,叫责任链模式 我翻阅了若干设计模式的书籍,对责任链模式基本上都是一笔带过没有过多的描述 关于责任链模式的写法,网上有很多,大多比较简单,而OkHttp的责任链写法比较独特。下面就采用OkHttp的写法 来实现一个简单的责任链模式,理解了这个责任链模式,也就理解了OkHttp的拦截器原理 ...

binghelonglong123的博客 492

《程序猿之设计模式实战 · 责任链模式》

本篇文章继续介绍一下责任链模式,这个在日常工作中使用较为频繁,责任链模式可以带给我们什么?SpringMVC的拦截器是否使用了责任链模式呢?让我们一探究竟。《程序猿之设计模式实战 · 策略模式》《程序猿之设计模式实战 · 装饰者模式》《程序猿之设计模式实战 · 池化思想》《程序猿之设计模式实战 · 观察者模式》1、责任链模式(Chain of Responsibility Pattern)是一种行为设计模式,它允许将请求的发送者和接收者解耦。

山人行 1399

响应结果拦截器_用责任链模式设计拦截器

我在 Redant(https://github.com/all4you/redant) 中通过继承 ChannelHandler 实现了拦截器的功能,并且 pipeline 就是一种责任链模式的应用。但是我后面对原本的拦截器进行了重新设计,为什么这样做呢,因为原本的方式是在 ChannelHandler 的基础上操作的,而我们知道 Netty 的数据处理都是基于 ByteBuf 的,这就涉及到引...

weixin_32110907的博客 244
上一篇: bootstrap+Ajax+SSM(maven搭建)表单增删改查
下一篇: Java程序员年薪40W是什么水平?税前还是税后?
javaQQ群 866865133
博客等级 码龄8年 59粉丝 309原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值