spring中怎么使用责任连模式


spring中怎么 香港云主机使用责任连模式,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。1. 外部控制模式
  对于外部控制的方式,这种方式比较简单,链的每个节点只需要专注于各自的逻辑即可,而当前节点调用完成之后是否继续调用下一个节点,这个则由外部控制逻辑决定。这里我们以一个过滤器的实现逻辑进行讲解,在平常工作中,我们经常需要根据一系列的条件对某个东西进行过滤,比如任务服务的设计,在执行某个任务,其需要经过诸如时效性的检验,风控拦截,任务完成次数等的过滤条件的检验之后才能判断当前任务是否能够执行,只有在所有的过滤条件都完成之后,我们才能执行该任务。那么,这里我们可以抽象出一个Filter接口,设计如下:  这里的Filter.filter方法只有一个参数Task,主要就是控制当天task是否需要过滤掉,其中有个boolean类型的返回值,通过该返回值告知外部控制逻辑是否需要将该task过滤掉。对于该接口的子类,我们只需要将其声明为spring所管理的一个bean即可:  上面我们模拟声明了3个Filter的子类,用于设计一系列的控制当天task是否需要被过滤的逻辑,结构上的逻辑其实比较简单,主要就是需要将其声明为spring所管理的一个bean。下面是我们的控制逻辑:  上述的控制逻辑中,对于过滤器的获取,只需要通过spring的自动注入即可,这里的注入是一个List,就是说,如果我们有新的Filter实例需要参与责任链的过滤,只需要声明为一个Spring容器所管理的bean即可。
  这种责任链设计方式的优点在于链的控制简单,只需要实现一个统一的接口即可,基本上满足大部分的逻辑控制,但是对于某些动态调整链的需求就无能为力了。比如在执行到某个节点之后需要动态的判断师傅执行下一个节点,或者说要执行,某些分叉点的节点等。这个时候,我们就需要将链节点的传递工作交个各个节点执行。
1. 外部控制模式
对于节点控制调用的方式,其主要有三个控制点:Handler,HandlerContext和PipeLine。Handle是用于编写具体的业务代码,HandlerContext用于对Handler进行包裹,并且用于控制下一个节点的调用;PipeLine则主要是用于控制整体的流程调用的,比如对于任务的执行,其有任务查询,任务的过滤和执行任务等等流程,这些流程整体的逻辑控制就是有pipeline控制,在每个流程中又包含了一些列的子流程,这些子流程则是由一个个的HandlerContext和Handler进行梳理的,这种责任链的控制方式整体逻辑如下图所示:![]
从上图可以看出,我们整个流程通过pipeline对象进行了抽象,这里主要分为了3个步骤:查询task,过滤task和执行task。在每个步骤中,我们都是用一系列的链式调用。途中需要注意的是,在每次调用链的下一个节点的时候,我们都是通过具体的Handler进行的,也就是说进行链的下一个节点的调用,我们是通过业务实现方来进行动态的控制。关于该模式的设计,我们首先需要强调的就是Handler接口的设计,其设计如下所示:这里的Handler接口主要是对具体的业务逻辑的一个抽象,对于该Handler主要有如下几点需要说明:在前面图中pipline的每个层级中对应于改Handler都有一个方法,在需要进行具体的业务处理的时候,用户只需要声明一个bean,具体实现某个业务所需要处理的层级的方法即可,无需管其他的逻辑;每个层级的方法都有默认的实现,默认实现方式就是将链的调用继续往下进行传递每个层级的方法中,第一个参数都是一个Handler类型的,该参数主要是用于进行流程控制的,比如是否需要将当前层级的调用链继续往下传递,这里的链的传递工作主要是通过ctx.filterXXX()方法进行每个Handler中都有一个exceptionCaught()和afterCompletion()方法,这两个方法分别用于异常的控制和所有调用完成之后的清理,这里的异常控制主要是捕获当前Handler中的异常,而afterCompetition()方法则会保证所有步骤之后一定会进行调用的,五路是否抛出异常;对于Handler的使用,我们希望能够达到的目的是,使用方只需要实现该接口,并且使用某个注解来将其标志位spring bean即可,无需管整个pipeline的组装和流程控制。通过这种方式,我们既保留了每个spring提供给我们的便利性,也使用了pipeline模式的灵活性
上述流程代码中,我们注意到,每个层级的方法中都有一个HandlerContext用于传递链的相关控制信息,我们来看下关于这部分的源码:在HandlerContext中,我们需要说明几点:之前Handler接口默认实现的ctx.filterXXX()方法,这里都委托给了对应的invokeXXX方法进行调用,而且我们注意到,在传递invokeXXX()方法的参数里,传入的HandlerContext对象都是通过next()方法获取到的。也就是说我们在Handler中调用ctx.filterXXX方法时,都是在调用当前Handler的下一个Handler对应的层级方法,通过这种方式我们就可以实现链式的传递调用;在上一点中我们说到,在某个Handler中如果想让链往下传递,只需要调用FilterXXX()方法即可,如果我们在某个Handler中,根据业务,当前层级已经调用完成,而无需调用后续的Handler,那么我们就不需要调用ctx.filterXXX()方法即可;在HandlerContext中,我们也实现了invokeXXX()方法,该方法的作用是提供给外部的pipeline调用的,开启每个层级的链;在每个invokeXXX()方法中,我们都是用try…catch将当前层级的调用抛出异常捕获了,然后调用ctx.handler().exceptionCaught()方法即可,异常捕获流程就是在这里的HandlerContext()中处理的;在HandlerContext的声明处,我们需要注意到,其使用了@conpoment和@(“prototype”)注解进行标注了,这说明我们的HandlerContext是有spring 容器管理的,并且由于我们每个Handler实际都由HandlerContext维护,所以这里必须声明为prototype类型。通过这种方式,我们的HandlerContext也就具备着诸如spring相关的bean的功能,能够根据业务需求进行一些额外的处理;
前面我们讲解了Handler和HandlerContext的具体实现,以及实现的过程需要注意的一些问题,下面我们将来看进行流程控制的pipeline是如何实现的,如下是其接口的定义:这里主要是定义了一个pipeline接口,该接口定义了一些列的层级调用,是每个层级的入口方法,如下是该接口的实现类:关于defaultPipeline的实现,有以下几点需要说明:defaultpipeline 使用@compoment和@scope(“prototype”)注解进行了标注,当前一个注解用于将其声明为一个spring容器所管理的bean,而后一个注解则用于表征defaultPipeline是个多例类型,很明显的,这里的pipeLine是有状态的。这里需要进行说明的是,’有状态’主要是因为我们可能会根据业务情况的动态的调整整个链的节点情况,而且这里的request和task对象都是与具体的业务相关的,因为必须声明为prototype类型;上面的示例中,request对象是通过构造pipeline对象的时候传进来的,而task对象则是在pipeline的流转过程中生成的,这里比如通过完成filterTaskReceived()链的调用之后,就需要通过外部请求request得到一个task对象,从而进行后续的处理;对于后续写业务代码的人而言,其只需要实现一个Handler接口即可,无需要处理链相关的所有逻辑,以为我们需要获取到所有实现Handler接口的bean;将实现了Handler接口的bean通过Handlercontext进行封装,然后将其添加到pipeline中
这里的第一个问题好处理,因为通过ApplicationContext就可以获取实现了某个接口的所有bean,而第二个问题我们可以通过声明了BeanPostProcessoor接口的类来实现。如下是具体的实现代码:这里我们整个链路的维护工作就完成,可以看到,现在基本已经实现了链式流程控制。这里需要说明的一点是,上面的HandlerBeanProcessor.postProcessAfterInitialization()方法的执行是在InitializingBean.afterPropertySet()方法之后执行的,也就是说这里的HandlerBeanProcessor在执行的时候,整个pipeline就是已经完成初始化的了。下面我们来看下外部客户端如何进行这个链路流程的控制:这里我们模拟一个客户端的调用,首先创建了一个pipeline对象,然后依次调用各个层级的方法,并且这里我们使用try….finally结构来保证Pipeline.fireAfterCompletion()方法一定会执行。如此我们就完成了整个责任链路模式的构造。这里我们使用前面用到的时效性的filter来作为示例来实现一个Handler:关于这里具体的业务我们需要说明的有如下几点:改Handler必须使用@compoment注解来将其声明为spring容器管理的bean,这样我们前面实现的HandlerBeanProcessor 才能动态的添加到整个pipeline中;在每个Handler中,需要根据当前的业务需要来实现具体的层级方法,比如这里是进行时效性检验的,就是”任务过滤”这一层级的逻辑,因为时效性检验通过我们才能执行这个task,因而这里需要实现的是Handler.filterTask()方法,如果我们需要实现的是执行task的逻辑,那么需要实现的是Handler.executeTask()方法; 在实现完具体的业务逻辑之后,我们可以根据当前的业务需要看是否需要将当前层级的链继续往下传递,也就是这里的ctx.fireTaskFiltered(task);方法的调用,我们可以看前面HandlerContext.fireXXX()方法就是会获取当前节点的下一个节点,然后进行调用。如果根据业务需要,不需要将链往下传递,那么就不需要调用ctx.fireTaskFiltered(task);看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注开发云行业资讯频道,感谢您对开发云的支持。

相关推荐: Flink Batch SQL 1.10 实践

Flink作为流批统一的计算框架,在1.10中完成了大量batch相关的增强与改进。1.10可以说是第一个成熟的生产可用的Flink Batch SQL版本,它一扫之前Dataset的羸弱,从功能和性能上都有大幅改进,以下我从架构、外部系统集成、实践三个方面进…

免责声明:本站发布的图片视频文字,以转载和分享为主,文章观点不代表本站立场,本站不承担相关法律责任;如果涉及侵权请联系邮箱:360163164@qq.com举报,并提供相关证据,经查实将立刻删除涉嫌侵权内容。

(0)
打赏 微信扫一扫 微信扫一扫
上一篇 07/26 20:51
下一篇 07/26 20:51

相关推荐