本文转载自微信公众号“源码兴趣圈”,作者龙泰。转载本文请联系源码兴趣圈公众号。前言文章开头提出了一个常见的问题。学习设计模式有什么作用?设计模式主要是处理代码的复杂性,使其满足开闭原则,提高代码的可扩展性。另外,学习的设计模式必须在业务代码中实现,只是理论没有实现,所以不可能真正掌握并灵活运用设计模式。这篇文章主要讲责任链设计模式。在阅读Mybatis的源码时,Interceptor拦截器主要使用责任链。当时看完,印象很深(内心OS:还可以这样玩)。文章从基本概念入手,在一波Mybatis源码中分析了它是如何使用的,最后根据“习惯”设计了一个真正的业务。场景中应用责任链设计模式的概要如下:什么是责任链模式?完成真正的责任链业务场景设计。MybatisInterceptor实现了底层的责任链模式。总结什么是责任链模式?比如拦截器可以在SpringMvc中定义,并且可以定义多个。当用户发起请求时,如果顺利的话,请求会经过所有的拦截器,最终到达业务代码逻辑。SpringMvc拦截器设计采用责任链模型。为什么它顺利通过所有拦截器?因为请求不满足拦截器定制的规则会被回调,但这并不是责任链模式的唯一处理方式。继续往下看。在责任链模式下,多个处理器(指上面的拦截器)依次处理同一个请求。一个请求先由A处理器处理,然后传递给B处理器,B处理器处理后再传递给C处理器,依此类推,形成一条链,链上的每个处理器负责自己的处理器ChainofResponsibility模式下由多个处理器组成的链在处理请求时有两种处理方式:请求会被所有处理器处理,没有中途终止。这里,参考MyBatis拦截处理器的理解是,在处理器链执行请求中,当一个处理器被执行时,如果不满足自制的规则,就会停止进程,其余未执行的处理器不会被执行执行。理解请参考SpringMvc拦截器,这里以代码的形式对两种处理方式进行了解答,方便读者更好的理解。先看第一个,请求会被所有处理器执行图1责任链模式一种实现IHandler负责抽象处理器行为,handle()是不同处理器具体需要执行的方法,HandleA和HandleB是具体的需要执行的处理器类,HandlerChain是将处理器串成一条链执行的处理器链。publicclassChainApplication{publicstaticvoidmain(String[]args){HandlerChainhandlerChain=newHandlerChain();newHandlerB()));handlerChain.handle();/***程序执行结果:*HandlerAprint:ExecuteHandlerA*HandlerBprint:ExecuteHandlerB*/}}这种责任链执行方式会把所有的processor执行一次,不会中断。这种类型被Mybatis拦截器使用,它专注于在请求过程中改变数据或行为。图2是指Mybatis拦截器的实现。责任链模式的另一种实现会阻塞请求。阻塞生成的前置条件是在处理器中自定义的,在代码中的实现比较简单。读者可以想到SpringMvc拦截器的实现流程图3.责任链模式的一种实现从代码中可以看出,在每个IHandler实现类中都会返回一个布尔返回值。如果返回的布尔值为false,责任链发起类将中断进程,其余处理器将不执行。就像我们在SpringMvc中定义的Token拦截器,如果Token失效,则无法继续访问系统,处理器会将请求回调到publicclassChainApplication{publicstaticvoidmain(String[]args){HandlerChainhandlerChain=newHandlerChain();handlerChain。addHandler(Lists.newArrayList(newHandlerA(),newHandlerB()));booleanresultFlag=handlerChain.handle();if(!resultFlag){System.out.println("责任链中的handler不满足条件");}}}读者可以在IDEA中实现两种不同的责任链模式。对比一下差异,想象一下业务中真实的应用场景,也可以运行SpringBoot项目,创建多个拦截器来支持文中的豪言壮语。图4参考SpringMvc拦截器的实现本章介绍责任链设计模式的具体语义,以及不同责任链实现类型的代码示例,并以Mybatis和SpringMvc拦截器为参考点介绍不同的代码实现和应用场景。责任链业务场景设计趁热打铁。用真实的业务场景来说明。假设业务场景是这样的,我们的系统在一个下游服务中。由于业务需求,系统中使用的基础数据需要从上游中台同步到系统数据库中。基础数据包含了很多类型的数据,虽然中台的数据会有一定的校验,但是只要是手工录入的数据,就可能会出现问题。为了遵守对上游系统不信任的原则,在接收到数据时需要进行一系列的验证。最初,需要一系列的验证原理才能入库。后来由于工期问题,只放了一套非空校验,趁着春节的时间,把这套校验规则骨架放进去。从我们系统的接入数据规则来看,个人感觉需要支持如下几套规则必填项校验,如果数据不能满足业务必填字段要求,一旦数据落入数据库,一系列的问题会出现。非法字符校验,因为我们不知道数据是怎么录入的,不知道上游系统的录入规则是什么。这些规则对于长度验证也是必需的。原因同上。如果系统中限制了某个字段的长度为50,但是传入的数据长度是500,这样也会出现问题。验证规则有两套,当然现实中可能不止这三套。但是,一旦在数据同步过程中嵌入责任链模式,将完全遵守文章开头提到的开闭原则,提高代码的可扩展性。本案例设计模式中的开闭原则是Spring支持的,后续会增加新的校验规则。您无需修改??原始代码。这里我要再次强调,设计模式的应用场景一定要灵活掌握。只有这样,对象的设计模式才能在合适的业务场景中合理使用。说完了设计模式的场景,接下来说说需要实现哪些业务需求。通过处理器链处理一批数据,返回符合要求的数据分类并不困难。定义顶层验证接口和一系列处理器实现类并不难,但是如何进行链式调用呢?这段代码需要一定的Spring基础才能看懂,我们来看看VerifyHandlerChain是如何将所有的处理器串成一条链的。VerifyHandlerChain的处理流程如下:从InitializingBean接口实现,在对应的实现方法中获取IOC容器中VerifyHandler类型的Bean,即EmptyVerifyHandler和SexyVerifyHandler。将bean添加到处理器链容器中,定义验证方法verify(),对入参数据启动对处理器链的所有调用。如果过程中没有需要校验的数据,直接返回这里使用SpringBoot工程中默认的测试类。下面测试一下如何调用@SpringBootTestclassChainApplicationTests{@AutowiredprivateVerifyHandlerChainverifyHandlerChain;@TestvoidcontextLoads(){List
