zoukankan      html  css  js  c++  java
  • 关于pipeline

    最近要将系统改造成pipeline架构,所以研究了一下pipeline相关的理论,servlet filter, struts2 interceptor, spring mvc interceptor, webx pipeline和netty pipeline的一些源码。一些总结:

    结构:

    1. Pipeline的类模型由Pipeline, Valve 和 Context 组成。 Pipeline代表一个执行流,Valve代表执行流中的一个节点,Context是执行时的上下文信息,它一般由两部分组成: request/response + 当前流的执行状态。

    2. 有的系统只能有一个Pipeline, 有的则允许配多个。 在struts2中,一种interceptor的组合,就代表了一个Pipeline;多种组合,意味着多个Pipeline.

    用法:

    1. 有的pipeline流是在同一层次上,每个valve处理的request/response对象基本上是同质的。比如servlet filter和各种mvc框架,所处理的事情都是web层的,所处理的context对象就是http request或框架自定义的javabean.

    2. 有的pipeline流则是纵向的,从上层流到下层,或从下层流到上层,这时每个valve所处理的request/response对象一般是异构的。协议栈就是个典型的例子:下层valve处理字节流,上层Valve处理字符流。 不过,为了适应pipeline架构,这些异构的context对象必须有共同的基类,并且把这个基类作为各个valve的输入参数。

    3. 从请求处理的角度来说, Pipeline可以代表整个执行流,也可以只用作请求被最终处理前的Interceptor. Webx, netty中的Pipeline会将最后一个Valve作为请求处理者(一般称为Request Handler),而servlet filter和struts2 interceptor只作请求拦截、加工,真正的请求处理者则是servlet和action.

    程序流:

    1. 一个完整的Pipeline执行流一般是个环路: Valve1 => Valve2 => Valve3 => Valve2 => Valve1. 从拦截的角度说,valve既是前置拦截(下一个valve执行前),又是后置拉截(下一个 valve执行后)。

    2. 为了达到前后双拦截的目标,程序实现有两种方法。 有一种方法是使用forEach方式分别执行每个拦截器的前置拦截方法,然后又以相反的顺序分别执行每个拦截器的后置拦截方法。这种做法比较直观,可以说直接映射了人类的思考方式。 Spring MVC Interceptor差不多就是这种做法。

    3. 另一种做法,也是主流的作法,则会把一个valve的执行嵌套在前一个valve的执行里面: 每个valve的执行中代码中会有一句"nextValve.invoke()",然后在这句代码的前后做一些拦截。这种方式有点费解,而且由于嵌套过多容易造成比较深的调用栈。 不过它有一个好处: 更方便地中断执行流并处理异常(下详)。

    4. 执行流须提供中断机制和异常处理机制,比如一个鉴权filter在发现用户未登录时需要立即返回403并中断流,当一个valve出现异常时这个异常需要被捕捉、处理。 如果Valve是嵌套执行的,这些机制会很方便实现: 鉴权filter发现用户未登录时,不调用nextValve.invoke()即可中断pipeline; 至于异常处理,Struts2默认使用ExceptionMappingInterceptor作为Pipeline中的第1个valve, 它会把nextIntercetpor.invoke()放在自己的try/catch块中。如果valve不是嵌套执行,而是由pipeline通过forEach编排执行的,那么这些非正常流的“扳道工”职责就必须由pipeline自己来承担, 这可能会使pipeline不够精简;如果来了新的逻辑(比如异步执行),又得改pipeline,导致pipeline不太稳定。

    设计模式:

    状态/无状态, 单例/非单例. 如果不怕麻烦,可以每来一个请求,就生成一个Pipeline对象和一堆Valve对象,再把request和上下文信息用作这些对象的状态;但是,用单例的风格更符合当代程序员的习惯,也更容易与spring结合。 那么,全单例并且都是无状态? 不尽然。虽然Pipeline的结构本身是静态的,一个pipeline结构可以作成一个单例;但Pipeline的执行流是有状态的,比如当前执行到了哪个valve,是需要一个变量来维护的。 所以,可以做一个单例的对象Pipeline, 代表Pipeline的结构;另做一个对象PipelineContext,代表Pipeline当前的执行流;至于Valve,它相当于一个stateless service, 做成单例即可.

  • 相关阅读:
    Windows Server 2016-配置Windows Defender防病毒排除项
    Windows Server 2016-增强IPAM
    第五讲:虚拟化架构、特点及优势
    第四讲:虚拟化概念及相关知识介绍
    第三讲:云计算的产生和特点
    第二讲:云分类及服务模式
    第一讲:云计算基础知识第一讲:云计算概念
    每天一个linux命令(56)--crontab命令
    每天一个linux命令(55)--at命令
    每天一个linux命令(54)--watch命令
  • 原文地址:https://www.cnblogs.com/wdmx/p/9895015.html
Copyright © 2011-2022 走看看