设计模式的应用——《职责链模式》

设计模式的应用——《职责链模式》

  • 一、职责链模式基础知识(What、Why、How)
    • 1、什么是职责链模式?
    • 2、如何使用职责链模式?——它的原理和实现
    • 3、为什么用职责链模式?
  • 二、什么场景下使用它?——职责链模式在框架和实际工作中的应用
    • Servlet Filter
    • Spring Interceptor
    • Dubbo Filter
  • 三、总结与思考
    • 1、Filter、Interceptor、AOP 都可以实现访问控制功能,它们之间的不同点是什么?
    • 2、和职责链模式相似的设计模式有哪些?
    • 3、职责链模式经常与哪些设计模式配合使用?

一、职责链模式基础知识(What、Why、How)

1、什么是职责链模式?

职责链模式,是一种行为型设计模式。它的目标在于将请求的发送和接收解耦,让多个接收对象都有机会处理这个请求。将这些接收对象串成一条链,并沿着这条链传递这个请求,直到链上的某个接收对象能够处理它为止。

2、如何使用职责链模式?——它的原理和实现

在我们实际的应用过程中,职责链模式有如下两种:

  • 将所有处理者连成一条链,并沿着这条链传递请求,直到有对象处理它为止
  • 请求会被所有的处理器都处理一遍,不存在中途终止的情况

如上两类职责链,仅仅是在处理方式上不一样,其他的都是一样的。我们的职责链模式主要包含两个角色:抽象处理者具体处理者
我们要实现一个职责链模式,首先,我们需要创建一个抽象处理者类(Handler),它包含一个指向下一个处理者的引用。然后,我们创建具体处理者类(ConcreteHandlerA和ConcreteHandlerB),它们分别实现抽象处理者类的方法。最后,我们创建一个客户端类(Client),它负责将请求传递给处理者链中的下一个处理者。
以下是第一类情况的示例代码:

import java.util.ArrayList;
import java.util.List;// 抽象处理者类
abstract class Handler {protected Handler successor;public void setSuccessor(Handler successor) {this.successor = successor;}public abstract void handleRequest(String request);
}// 具体处理者A类
class ConcreteHandlerA extends Handler {@Overridepublic void handleRequest(String request) {if (request.equals("A")) {System.out.println("ConcreteHandlerA处理请求");} else {if (successor != null) {successor.handleRequest(request);} else {System.out.println("没有合适的处理器处理请求");}}}
}// 具体处理者B类
class ConcreteHandlerB extends Handler {@Overridepublic void handleRequest(String request) {if (request.equals("B")) {System.out.println("ConcreteHandlerB处理请求");} else {if (successor != null) {successor.handleRequest(request);} else {System.out.println("没有合适的处理器处理请求");}}}
}// 客户端类
class Client {private List<Handler> handlers = new ArrayList<>();public Client() {handlers.add(new ConcreteHandlerA());handlers.add(new ConcreteHandlerB());for (int i = 0; i < handlers.size() - 1; i++) {handlers.get(i).setSuccessor(handlers.get(i + 1));}}public void sendRequest(String request) {for (Handler handler : handlers) {handler.handleRequest(request);}}
}public class Main {public static void main(String[] args) {Client client = new Client();client.sendRequest("A"); // 输出:ConcreteHandlerA处理请求client.sendRequest("B"); // 输出:ConcreteHandlerB处理请求client.sendRequest("C"); // 输出:没有合适的处理器处理请求}
}

3、为什么用职责链模式?

既然我们用它,那我们就要讲讲它的优点啦!职责链模式有如下优点:

  • 请求与处理解耦

在职责链模式中,处理者只需关心自己的处理逻辑,如果不是自己的处理的请求直接转发,降低了对象间的耦合性。

  • 链式传递功能

一个请求可以在一条链上进行传递,直到链上的某一个节点决定处理此请求。这种结构使得请求者无须了解链路的结构,只需要将请求发送出去,等待结果返回即可。

  • 易于维护和拓展

由于职责链模式遵循开闭原则,可以灵活地修改链路结构,比如新增或删除环境。另外, 可以灵活动态的选择需要哪些职责。

  • 增强系统的可扩展性

符合开闭原则,当我们需要添加新的职责时,我们只需添加新的职责类,并且添加到执行链中去即可。而无需修改其他代码。

二、什么场景下使用它?——职责链模式在框架和实际工作中的应用

职责链在很多框架中都有使用,下面仅介绍在Servlet Filter、Spring Interceptor以及dubbo Filter中的使用。

Servlet Filter

Servlet Filter是Java Web开发中用于对请求和响应进行处理的过滤器。它可以在请求到达目标资源之前或响应返回客户端之前执行一些操作,例如验证用户身份、记录日志、压缩响应等。Servlet Filter通常通过实现javax.servlet.Filter接口来定义。

以下是一个简单的Servlet Filter示例:

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;public class MyFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {// 初始化过滤器时执行的操作,例如加载配置文件}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {// 在请求到达目标资源之前执行的操作System.out.println("请求被MyFilter处理");// 继续执行过滤器链中的下一个过滤器或目标资源chain.doFilter(request, response);// 在响应返回客户端之后执行的操作System.out.println("响应被MyFilter处理");}@Overridepublic void destroy() {// 销毁过滤器时执行的操作,例如释放资源}
}

要使用这个过滤器,需要在web.xml文件中进行配置:

<filter><filter-name>myFilter</filter-name><filter-class>com.example.MyFilter</filter-class>
</filter>
<filter-mapping><filter-name>myFilter</filter-name><url-pattern>/*</url-pattern>
</filter-mapping>

Spring Interceptor

在Spring框架中,拦截器(Interceptor)是一种用于处理请求和响应的机制。通过使用拦截器,我们可以实现职责链模式,将多个拦截器按照顺序组合起来,以便在一个请求到达目标资源之前或之后执行特定的操作。

以下是一个简单的示例,展示了如何在Spring拦截器中使用职责链模式:
1、首先,创建一个拦截器接口HandlerInterceptor,并定义一个方法preHandle,该方法将在请求到达目标资源之前执行:

public interface HandlerInterceptor {boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler);
}

2、然后,创建一个具体的拦截器类MyInterceptor,实现HandlerInterceptor接口,并在preHandle方法中实现职责链模式的逻辑:

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class MyInterceptor implements HandlerInterceptor {private HandlerInterceptor nextInterceptor;public MyInterceptor(HandlerInterceptor nextInterceptor) {this.nextInterceptor = nextInterceptor;}@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {// 在这里实现你的职责链逻辑System.out.println("MyInterceptor: preHandle");// 如果当前拦截器没有处理完请求,将请求传递给下一个拦截器if (nextInterceptor != null) {return nextInterceptor.preHandle(request, response, handler);}// 如果当前拦截器已经处理完请求,返回truereturn true;}
}

3、接下来,创建一个配置类WebMvcConfig,用于注册拦截器并配置拦截器的执行顺序:

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class WebMvcConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {// 注册第一个拦截器,并设置其执行顺序为1registry.addInterceptor(new MyInterceptor(null)).addPathPatterns("/**").order(1);// 注册第二个拦截器,并设置其执行顺序为2registry.addInterceptor(new MyInterceptor(new MyInterceptor(null))).addPathPatterns("/**").order(2);}
}

在这个示例中,我们创建了两个拦截器MyInterceptor,并将它们按照顺序添加到拦截器注册表中。当一个请求到达目标资源时,Spring会按照拦截器的执行顺序依次调用它们的preHandle方法。如果某个拦截器没有处理完请求,它会将请求传递给下一个拦截器。

Dubbo Filter

Dubbo中的过滤器(Filter)是一种用于处理请求和响应的中间件。它可以在服务提供者和消费者之间对请求进行预处理、后处理或者拦截,从而实现对请求和响应的定制化处理。Dubbo支持多种类型的过滤器,如:

协议过滤器(Protocol Filter):用于处理请求和响应的序列化和反序列化,例如将Java对象转换为JSON字符串,或将JSON字符串转换为Java对象。
路由过滤器(Routing Filter):用于根据条件选择不同的服务提供者或消费者,例如基于权重、随机、轮询等策略进行负载均衡。
指标过滤器(Metrics Filter):用于收集和统计服务的调用次数、响应时间等信息,以便进行性能监控和优化。
限流过滤器(RateLimiting Filter):用于限制服务的调用速率,以防止系统过载。
安全过滤器(Security Filter):用于验证请求的身份信息,例如使用OAuth2、JWT等认证机制。
要使用过滤器,需要在Dubbo配置文件中进行配置。例如,使用dubbo:protocol标签配置协议过滤器:

<dubbo:protocol name="dubbo" port="20880" />
<dubbo:protocol name="http" port="8080" filter="statistic" />

在这个例子中,我们为Dubbo协议配置了一个名为statistic的过滤器,该过滤器会在请求和响应之间收集统计信息。

下面是Dubbo中RandomRouterFilterWrapper的源码, 该类继承自AbstractRouter,并实现了route方法。在route方法中,首先通过扩展点获取随机路由过滤器,如果存在则调用其route方法进行路由;如果不存在,则使用默认的路由规则。同时,还实现了getAlgorithmName和compare方法,分别返回算法名称和比较结果。

import org.apache.dubbo.common.Constants;
import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.rpc.RpcContext;
import org.apache.dubbo.rpc.router.AbstractRouter;
import org.apache.dubbo.rpc.router.RouteRule;import java.util.List;
import java.util.Random;public class RandomRouterFilterWrapper extends AbstractRouter {private final Random random = new Random();@Overridepublic List<RouteRule> route(List<RouteRule> rules, RpcContext context) {// 获取扩展点中的随机路由过滤器RandomRouterFilter filter = ExtensionLoader.getExtensionLoader(RandomRouterFilter.class).getExtension(Constants.DEFAULT_EXTENSION_NAME);if (filter != null) {return filter.route(rules, context);}// 如果没有配置随机路由过滤器,则使用默认的路由规则return super.route(rules, context);}@Overridepublic String getAlgorithmName() {return "random";}@Overridepublic int compare(String o1, String o2) {return random.nextInt(2) - 1;}
}

三、总结与思考

职责链设计模式常常在开发框架中使用,用来实现框架的过滤器、拦截器功能,让框架的使用者在不需要对源码进行修改的情况下,添加新的过滤拦截功能,体现了开闭原则。但具体每个框架的实现会根据实际的需求来设计。下面是关于职责链模式的一些思考,分享给大家:

1、Filter、Interceptor、AOP 都可以实现访问控制功能,它们之间的不同点是什么?

Filter、Interceptor和AOP都可以实现访问控制功能,这是它们的相同点。然而,它们在实现和使用上存在一些不同点。

  • 过滤器(Filter)属于Servlet规范,主要拦截web访问的url地址。其工作原理基于Tomcat提供的接口,直接对请求和响应进行处理。

  • 拦截器(Interceptor)依赖于Spring框架,主要拦截以.action结尾的url,以及Action的访问。拦截器关注的是接口执行前和执行后要做的事,并且只能拦截controller的请求。

  • Spring AOP拦截器是基于Spring AOP实现的,它只能拦截Spring管理Bean的访问,如业务层Service。与过滤器和拦截器不同的是,Spring AOP关注的是方法执行前后要做的事情。
    该三者的拦截顺序是分级的,优先级从高到低依次是:Filter、Interceptor、AOP。但在某些特殊情况下,也可以通过调整配置来改变这个顺序。例如,在Spring Boot中,可以通过配置文件来改变拦截器的执行顺序。

2、和职责链模式相似的设计模式有哪些?

  • 命令模式(Command Pattern):此模式也是一种行为型模式,类似于职责链模式,它也通过将请求封装成对象来达到解耦的目的。不过命令模式中的命令对象会包含与请求相关的信息,比如请求的接收者、方法名等。

  • 解释器模式(Interpreter Pattern):该模式同样属于行为型模式,它通过定义语言的文法以及解析规则来解析语言。这与职责链模式中多个处理者按顺序处理请求的方式相似。

  • 中介者模式(Mediator Pattern):这是一种结构型模式,它通过引入一个中介者对象来解除原有对象之间的依赖关系,从而降低系统的耦合度。这与职责链模式中的处理者链条有异曲同工之妙。

  • 观察者模式(Observer Pattern):这也是一种行为型模式,它通过定义一对多的通知机制来实现当一个对象状态改变时,所有依赖于它的对象都会得到通知并自动更新。这和职责链模式中每个处理者都只负责处理自己感兴趣的请求,然后将其转发给后续的处理者的思想很相似。

3、职责链模式经常与哪些设计模式配合使用?

  • 简单工厂模式:在创建处理者对象时,可以使用简单工厂模式来封装对象的创建过程和逻辑。
  • 观察者模式:可以在处理者中加入对其他处理者的引用,然后动态的插入和移除后续处理者,以改变处理顺序。
  • 单例模式:对于某些需要保证唯一性的处理者,可以采用单例模式来确保在整个系统中只有一个实例存在。
  • 模板方法模式:可以在一个处理者的基类中定义一些算法的框架,而将具体实现延迟到子类中。这样,客户端可以通过调用基类的算法接口来达到处理请求的目的,而不需要直接访问子类。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/228354.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux---进程概念

目录 一、冯诺依曼体系结构 二、操作系统 1.关于下三层的理解 2.关于上三层的理解 三、进程 1.进程(也叫做任务)对应的标识符---pid 2.fork---用代码创建进程(系统接口) 1&#xff09;初步认识一下fork 2&#xff09;fork函数的返回值 3&#xff09;fork的原理 问题1…

虚拟机性能监控、故障处理工具

虚拟机性能监控、故障处理工具 二、基础故障处理工具4.2.1 jps&#xff1a;虚拟机进程状况工具4.2.2 jstat:虚拟机统计信息监视工具4.2.3 jinfo:Java配置信息工具4.2.4 jmap:java内存映像工具4.2.5 jhat:虚拟机堆转储快照分析工具4.2.6 jstack&#xff1a;Java堆栈跟踪工具4.2.…

四舍五入浮点数

1.题目如下&#xff1a; 2.方法一&#xff1a; 直接取出小数部分第一位来判断。 1. 先乘以10。 2. 强制类型转换为整型&#xff0c;去掉小数部分。 3. 再模10&#xff0c;相当于取出原数的小数第一位。 代码实现&#xff1a; int way1(double n) {int a (int)(n * 10);int b…

c#的event使用(1)

在C#中&#xff0c;事件是一种用于在类或对象之间进行通信的机制。当某个特定的事件发生时&#xff0c;与该事件相关联的方法&#xff08;称为事件处理程序&#xff09;将被调用。 下面是使用C#事件的基本步骤&#xff1a; 定义事件&#xff1a;在类中定义一个事件成员变量&a…

后端开发——统一处理异常Spring MVC机制

一、Spring MVC的统一处理异常机制 在Spring MVC中&#xff0c;存在统一处理异常的机制&#xff0c; 具体表现为&#xff1a;无论是哪个处理请求的过程中出现异常&#xff0c;每种类型的异常只需要编写一段处理异常的代码即可&#xff01; 统一处理异常的核心是定义处理异常的…

【k8s】使用Finalizers控制k8s资源删除

文章目录 词汇表基本删除操作Finalizers是什么&#xff1f;Owner References又是什么&#xff1f;强制删除命名空间参考 你有没有在使用k8s过程中遇到过这种情况: 通过kubectl delete指令删除一些资源时&#xff0c;一直处于Terminating状态。 这是为什么呢&#xff1f; 本文将…

普冉(PUYA)单片机开发笔记(12): 获取外部中断

概述 将单片机的 GPIO 引脚作为外部按键的输入端是单片机较为常用的方式&#xff0c;例如把这颗 MCU 部署在一块控制面板的触点底板&#xff0c;使用者按压按钮&#xff08;按键&#xff09;对产品进行控制。本着学以致用的原则&#xff0c;使用 PY32F003 对外部中断如何处理是…

【漏洞复现】系列集合

该篇文章仅供学习网络安全技术参考研究使用&#xff0c;请勿使用相关技术做违法操作 Apache Apache_HTTPD_未知后缀名解析Apache_HTTPD_换行解析(CVE-2017-15715)Apache_HTTPD_多后缀解析Apache_HTTP_2.4.50_路径穿越(CVE-2021-42013)Apache_HTTP_2.4.49_路径穿越(CVE-2021-41…

智能优化算法应用:基于静电放电算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于静电放电算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于静电放电算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.静电放电算法4.实验参数设定5.算法结果6.…

高效网络爬虫:代理IP的应用与实践

&#x1f482; 个人网站:【 海拥】【神级代码资源网站】【办公神器】&#x1f91f; 基于Web端打造的&#xff1a;&#x1f449;轻量化工具创作平台&#x1f91f; 代理 IP 推荐&#xff1a;&#x1f449;品易 HTTP 代理 IP &#x1f485; 想寻找共同学习交流的小伙伴&#xff0c…

Flink系列之:State Time-To-Live (TTL)

Flink系列之&#xff1a;State Time-To-Live TTL 一、TTL二、TTL实现代码三、过期状态的清理 一、TTL Flink的TTL&#xff08;Time-To-Live&#xff09;是一种数据过期策略&#xff0c;用于指定数据在流处理中的存活时间。TTL可以应用于Flink中的状态或事件时间窗口&#xff0…

FME之FeatureReader转换器按表格内容读取矢量数据

问题&#xff1a;平时会遇到只用某个大数据里某小部分数据参与下一步数据处理&#xff0c;此时我们会用到FeatureReader转换器&#xff0c;一般是通过空间关系&#xff08;相交、包含&#xff09;来读取相应涉及的图斑矢量&#xff0c;但就有一个问题&#xff0c;加入你的启动器…

太强了!利用 Python 连接 ES 查询索引某个字段命中数的脚本!

作者&#xff1a;JackTian 来源&#xff1a;公众号「杰哥的IT之旅」 ID&#xff1a;Jake_Internet 链接&#xff1a;太强了&#xff01;利用 Python 连接 ES 查询索引某个字段命中数的脚本&#xff01; 当我们在工作中&#xff0c;如果频繁查询 Elasticsearch 某个索引中的某个…

关于laravel的逻辑删除deleted_at与mysql唯一索引unique

使用mysql组合key去设置唯一索引unique时&#xff0c;可以避免因各种原因导致的重复脏数据问题&#xff0c;但由于我们绝大多数表都不建议采取物理删除的方式去对待可爱的数据们&#xff0c;因此我们常常使用逻辑删除&#xff08;软删除&#xff09;的方式去对错误数据或无效数…

计算机视觉(P2)-计算机视觉任务和应用

一、说明 在本文中&#xff0c;我们将探讨主要的计算机视觉任务以及每个任务最流行的应用程序。 二、图像内容分类 2.1. 图像分类 图像分类是计算机视觉领域的主要任务之一[1]。在该任务中&#xff0c;经过训练的模型根据预定义的类集为图像分配特定的类。下图是著名的CIFAR…

格式化Echarts的X轴显示,设置显示间隔

业务需求&#xff1a;x轴间隔4个显示&#xff0c;并且末尾显示23时 x轴为写死的0时-23时&#xff0c;使用Array.from data: Array.from({ length: 24 }).map((_, i) > ${i}时) 需要在axisLabel 里使用 interval: 0, // 强制显示所有刻度标签&#xff0c;然后通过 formatter …

分面中添加不同表格

简介 关于分面的推文&#xff0c;小编根据实际科研需求&#xff0c;已经分享了很多技巧。例如&#xff1a; 分面一页多图 基于分面的面积图绘制 分面中的细节调整汇总 分面中添加不同的直线 基于分面的折线图绘制 最近遇到了另一个需求&#xff1a;在分面中添加不同的表…

k8s 安装firewalld导致的网络疑难问题处理

场景 ubuntu 操作系统,部署了k8s集群,n 台 机器,某些机器之间 telnet ip 10250不通。 ufw 是关闭的,然后抓包会看到如下错误 04:43:09.154362 IP 192.168.1.3.56608 > 192.168.1.183.8000: Flags [S], seq 3664350430, win 64240, options [mss 1460,sackOK,TS val 281…

计算机网络(四)

九、网络安全 &#xff08;一&#xff09;什么是网络安全&#xff1f; A、网络安全状况 分布式反射攻击逐渐成为拒绝攻击的重要形式 涉及重要行业和政府部门的高危漏洞事件增多。 基础应用和通用软硬件漏洞风险凸显&#xff08;“心脏出血”&#xff0c;“破壳”等&#x…

Content-Type是什么

目录 Content-Type是什么 获取方式 设置方式 常见类型 application/x-www-form-urlencoded multipart/form-data application/json text/xml text/html text/plain Content-Type是什么 Content-Type出现在请求标头和响应标头中&#xff0c;意思是内容类型&#xff0…