责任链模式详解:从Servlet过滤器到订单创建流程

责任链模式适合处理"一个请求要经过多个步骤"的场景。

比如订单创建,要先校验参数,再补充数据,再算价,再落库。内容审核,要先文本审核,再图片审核,再视频审核。Web 请求进入服务前,也可能经过鉴权、限流、日志、跨域等多个过滤器。

一句话概括:责任链模式把多个处理节点串成一条链,请求沿着链向后传递,每个节点只负责自己的职责。

责任链解决什么问题

不用责任链时,订单创建可能写成这样:

java 复制代码
public void createOrder(OrderInfo order) {
    validate(order);
    fillOrder(order);
    calculateAmount(order);
    saveOrder(order);
}

这段代码看起来不复杂,但问题在于流程和步骤绑死了。

如果要在算价前加一个优惠券校验,或者在落库后加返佣处理,就要修改主流程。
#mermaid-svg-FdwIvLUGzPWg2n02{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-FdwIvLUGzPWg2n02 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-FdwIvLUGzPWg2n02 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-FdwIvLUGzPWg2n02 .error-icon{fill:#552222;}#mermaid-svg-FdwIvLUGzPWg2n02 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-FdwIvLUGzPWg2n02 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-FdwIvLUGzPWg2n02 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-FdwIvLUGzPWg2n02 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-FdwIvLUGzPWg2n02 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-FdwIvLUGzPWg2n02 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-FdwIvLUGzPWg2n02 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-FdwIvLUGzPWg2n02 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-FdwIvLUGzPWg2n02 .marker.cross{stroke:#333333;}#mermaid-svg-FdwIvLUGzPWg2n02 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-FdwIvLUGzPWg2n02 p{margin:0;}#mermaid-svg-FdwIvLUGzPWg2n02 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-FdwIvLUGzPWg2n02 .cluster-label text{fill:#333;}#mermaid-svg-FdwIvLUGzPWg2n02 .cluster-label span{color:#333;}#mermaid-svg-FdwIvLUGzPWg2n02 .cluster-label span p{background-color:transparent;}#mermaid-svg-FdwIvLUGzPWg2n02 .label text,#mermaid-svg-FdwIvLUGzPWg2n02 span{fill:#333;color:#333;}#mermaid-svg-FdwIvLUGzPWg2n02 .node rect,#mermaid-svg-FdwIvLUGzPWg2n02 .node circle,#mermaid-svg-FdwIvLUGzPWg2n02 .node ellipse,#mermaid-svg-FdwIvLUGzPWg2n02 .node polygon,#mermaid-svg-FdwIvLUGzPWg2n02 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-FdwIvLUGzPWg2n02 .rough-node .label text,#mermaid-svg-FdwIvLUGzPWg2n02 .node .label text,#mermaid-svg-FdwIvLUGzPWg2n02 .image-shape .label,#mermaid-svg-FdwIvLUGzPWg2n02 .icon-shape .label{text-anchor:middle;}#mermaid-svg-FdwIvLUGzPWg2n02 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-FdwIvLUGzPWg2n02 .rough-node .label,#mermaid-svg-FdwIvLUGzPWg2n02 .node .label,#mermaid-svg-FdwIvLUGzPWg2n02 .image-shape .label,#mermaid-svg-FdwIvLUGzPWg2n02 .icon-shape .label{text-align:center;}#mermaid-svg-FdwIvLUGzPWg2n02 .node.clickable{cursor:pointer;}#mermaid-svg-FdwIvLUGzPWg2n02 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-FdwIvLUGzPWg2n02 .arrowheadPath{fill:#333333;}#mermaid-svg-FdwIvLUGzPWg2n02 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-FdwIvLUGzPWg2n02 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-FdwIvLUGzPWg2n02 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-FdwIvLUGzPWg2n02 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-FdwIvLUGzPWg2n02 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-FdwIvLUGzPWg2n02 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-FdwIvLUGzPWg2n02 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-FdwIvLUGzPWg2n02 .cluster text{fill:#333;}#mermaid-svg-FdwIvLUGzPWg2n02 .cluster span{color:#333;}#mermaid-svg-FdwIvLUGzPWg2n02 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-FdwIvLUGzPWg2n02 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-FdwIvLUGzPWg2n02 rect.text{fill:none;stroke-width:0;}#mermaid-svg-FdwIvLUGzPWg2n02 .icon-shape,#mermaid-svg-FdwIvLUGzPWg2n02 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-FdwIvLUGzPWg2n02 .icon-shape p,#mermaid-svg-FdwIvLUGzPWg2n02 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-FdwIvLUGzPWg2n02 .icon-shape .label rect,#mermaid-svg-FdwIvLUGzPWg2n02 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-FdwIvLUGzPWg2n02 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-FdwIvLUGzPWg2n02 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-FdwIvLUGzPWg2n02 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 订单创建方法
校验参数
填充订单
计算金额
订单落库

责任链的做法是把每个步骤变成独立处理器,然后把处理器串起来。
#mermaid-svg-mScwa5wpQU5SaHRs{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-mScwa5wpQU5SaHRs .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-mScwa5wpQU5SaHRs .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-mScwa5wpQU5SaHRs .error-icon{fill:#552222;}#mermaid-svg-mScwa5wpQU5SaHRs .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-mScwa5wpQU5SaHRs .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-mScwa5wpQU5SaHRs .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-mScwa5wpQU5SaHRs .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-mScwa5wpQU5SaHRs .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-mScwa5wpQU5SaHRs .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-mScwa5wpQU5SaHRs .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-mScwa5wpQU5SaHRs .marker{fill:#333333;stroke:#333333;}#mermaid-svg-mScwa5wpQU5SaHRs .marker.cross{stroke:#333333;}#mermaid-svg-mScwa5wpQU5SaHRs svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-mScwa5wpQU5SaHRs p{margin:0;}#mermaid-svg-mScwa5wpQU5SaHRs .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-mScwa5wpQU5SaHRs .cluster-label text{fill:#333;}#mermaid-svg-mScwa5wpQU5SaHRs .cluster-label span{color:#333;}#mermaid-svg-mScwa5wpQU5SaHRs .cluster-label span p{background-color:transparent;}#mermaid-svg-mScwa5wpQU5SaHRs .label text,#mermaid-svg-mScwa5wpQU5SaHRs span{fill:#333;color:#333;}#mermaid-svg-mScwa5wpQU5SaHRs .node rect,#mermaid-svg-mScwa5wpQU5SaHRs .node circle,#mermaid-svg-mScwa5wpQU5SaHRs .node ellipse,#mermaid-svg-mScwa5wpQU5SaHRs .node polygon,#mermaid-svg-mScwa5wpQU5SaHRs .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-mScwa5wpQU5SaHRs .rough-node .label text,#mermaid-svg-mScwa5wpQU5SaHRs .node .label text,#mermaid-svg-mScwa5wpQU5SaHRs .image-shape .label,#mermaid-svg-mScwa5wpQU5SaHRs .icon-shape .label{text-anchor:middle;}#mermaid-svg-mScwa5wpQU5SaHRs .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-mScwa5wpQU5SaHRs .rough-node .label,#mermaid-svg-mScwa5wpQU5SaHRs .node .label,#mermaid-svg-mScwa5wpQU5SaHRs .image-shape .label,#mermaid-svg-mScwa5wpQU5SaHRs .icon-shape .label{text-align:center;}#mermaid-svg-mScwa5wpQU5SaHRs .node.clickable{cursor:pointer;}#mermaid-svg-mScwa5wpQU5SaHRs .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-mScwa5wpQU5SaHRs .arrowheadPath{fill:#333333;}#mermaid-svg-mScwa5wpQU5SaHRs .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-mScwa5wpQU5SaHRs .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-mScwa5wpQU5SaHRs .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-mScwa5wpQU5SaHRs .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-mScwa5wpQU5SaHRs .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-mScwa5wpQU5SaHRs .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-mScwa5wpQU5SaHRs .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-mScwa5wpQU5SaHRs .cluster text{fill:#333;}#mermaid-svg-mScwa5wpQU5SaHRs .cluster span{color:#333;}#mermaid-svg-mScwa5wpQU5SaHRs div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-mScwa5wpQU5SaHRs .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-mScwa5wpQU5SaHRs rect.text{fill:none;stroke-width:0;}#mermaid-svg-mScwa5wpQU5SaHRs .icon-shape,#mermaid-svg-mScwa5wpQU5SaHRs .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-mScwa5wpQU5SaHRs .icon-shape p,#mermaid-svg-mScwa5wpQU5SaHRs .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-mScwa5wpQU5SaHRs .icon-shape .label rect,#mermaid-svg-mScwa5wpQU5SaHRs .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-mScwa5wpQU5SaHRs .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-mScwa5wpQU5SaHRs .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-mScwa5wpQU5SaHRs :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 订单请求
参数校验处理器
订单填充处理器
金额计算处理器
订单落库处理器
处理完成

每个处理器只关心自己要做什么,以及要不要把请求交给下一个处理器。

责任链的三个角色

角色 作用
抽象处理者 定义处理方法,并保存下一个处理器引用
具体处理者 实现自己的处理逻辑
客户端 组装链路,并把请求交给链头

抽象处理器可以这样写:

java 复制代码
public abstract class Handler {

    protected Handler next;

    public void setNext(Handler next) {
        this.next = next;
    }

    public abstract void process(OrderInfo order);
}

具体处理器做完自己的事后,把请求交给下一个节点:

java 复制代码
public class OrderValidation extends Handler {
    @Override
    public void process(OrderInfo order) {
        // 校验订单参数
        if (next != null) {
            next.process(order);
        }
    }
}

组装链路:

java 复制代码
Handler validation = new OrderValidation();
Handler fill = new OrderFill();
Handler amount = new OrderAmountCalculate();
Handler create = new OrderCreate();

validation.setNext(fill);
fill.setNext(amount);
amount.setNext(create);

validation.process(new OrderInfo());

"订单落库" "金额计算" "订单填充" "参数校验" "客户端" "订单落库" "金额计算" "订单填充" "参数校验" "客户端" #mermaid-svg-mc6AdPvOvCcTGX8W{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-mc6AdPvOvCcTGX8W .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-mc6AdPvOvCcTGX8W .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-mc6AdPvOvCcTGX8W .error-icon{fill:#552222;}#mermaid-svg-mc6AdPvOvCcTGX8W .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-mc6AdPvOvCcTGX8W .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-mc6AdPvOvCcTGX8W .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-mc6AdPvOvCcTGX8W .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-mc6AdPvOvCcTGX8W .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-mc6AdPvOvCcTGX8W .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-mc6AdPvOvCcTGX8W .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-mc6AdPvOvCcTGX8W .marker{fill:#333333;stroke:#333333;}#mermaid-svg-mc6AdPvOvCcTGX8W .marker.cross{stroke:#333333;}#mermaid-svg-mc6AdPvOvCcTGX8W svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-mc6AdPvOvCcTGX8W p{margin:0;}#mermaid-svg-mc6AdPvOvCcTGX8W .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-mc6AdPvOvCcTGX8W text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-mc6AdPvOvCcTGX8W .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-mc6AdPvOvCcTGX8W .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-mc6AdPvOvCcTGX8W .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-mc6AdPvOvCcTGX8W .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-mc6AdPvOvCcTGX8W #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-mc6AdPvOvCcTGX8W .sequenceNumber{fill:white;}#mermaid-svg-mc6AdPvOvCcTGX8W #sequencenumber{fill:#333;}#mermaid-svg-mc6AdPvOvCcTGX8W #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-mc6AdPvOvCcTGX8W .messageText{fill:#333;stroke:none;}#mermaid-svg-mc6AdPvOvCcTGX8W .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-mc6AdPvOvCcTGX8W .labelText,#mermaid-svg-mc6AdPvOvCcTGX8W .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-mc6AdPvOvCcTGX8W .loopText,#mermaid-svg-mc6AdPvOvCcTGX8W .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-mc6AdPvOvCcTGX8W .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-mc6AdPvOvCcTGX8W .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-mc6AdPvOvCcTGX8W .noteText,#mermaid-svg-mc6AdPvOvCcTGX8W .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-mc6AdPvOvCcTGX8W .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-mc6AdPvOvCcTGX8W .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-mc6AdPvOvCcTGX8W .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-mc6AdPvOvCcTGX8W .actorPopupMenu{position:absolute;}#mermaid-svg-mc6AdPvOvCcTGX8W .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-mc6AdPvOvCcTGX8W .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-mc6AdPvOvCcTGX8W .actor-man circle,#mermaid-svg-mc6AdPvOvCcTGX8W line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-mc6AdPvOvCcTGX8W :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} "提交订单""校验通过,继续""填充完成,继续""算价完成,继续""订单创建完成"

责任链和普通流程编排有什么区别

普通流程编排通常由一个方法集中调用所有步骤:

java 复制代码
validate();
fill();
calculate();
save();

责任链则把"下一个步骤是谁"交给处理器或链路配置管理。

对比项 普通流程 责任链
步骤关系 主流程硬编码 节点串联
扩展方式 修改主流程 新增处理器并调整链路
节点职责 可能混在主流程 每个节点职责独立
适合场景 流程固定且简单 步骤较多、可插拔、可扩展

责任链不是为了让所有流程都变复杂。它适合步骤多、扩展频繁、每个步骤能独立表达的场景。

Servlet Filter 也是典型责任链

Web 请求进入服务时,经常要经过多个过滤器:

  1. 跨域处理
  2. 日志记录
  3. 登录校验
  4. 权限校验
  5. 限流处理
  6. Controller 方法

#mermaid-svg-xwhMU06CmJoIDpF5{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-xwhMU06CmJoIDpF5 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-xwhMU06CmJoIDpF5 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-xwhMU06CmJoIDpF5 .error-icon{fill:#552222;}#mermaid-svg-xwhMU06CmJoIDpF5 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-xwhMU06CmJoIDpF5 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-xwhMU06CmJoIDpF5 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-xwhMU06CmJoIDpF5 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-xwhMU06CmJoIDpF5 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-xwhMU06CmJoIDpF5 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-xwhMU06CmJoIDpF5 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-xwhMU06CmJoIDpF5 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-xwhMU06CmJoIDpF5 .marker.cross{stroke:#333333;}#mermaid-svg-xwhMU06CmJoIDpF5 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-xwhMU06CmJoIDpF5 p{margin:0;}#mermaid-svg-xwhMU06CmJoIDpF5 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-xwhMU06CmJoIDpF5 .cluster-label text{fill:#333;}#mermaid-svg-xwhMU06CmJoIDpF5 .cluster-label span{color:#333;}#mermaid-svg-xwhMU06CmJoIDpF5 .cluster-label span p{background-color:transparent;}#mermaid-svg-xwhMU06CmJoIDpF5 .label text,#mermaid-svg-xwhMU06CmJoIDpF5 span{fill:#333;color:#333;}#mermaid-svg-xwhMU06CmJoIDpF5 .node rect,#mermaid-svg-xwhMU06CmJoIDpF5 .node circle,#mermaid-svg-xwhMU06CmJoIDpF5 .node ellipse,#mermaid-svg-xwhMU06CmJoIDpF5 .node polygon,#mermaid-svg-xwhMU06CmJoIDpF5 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-xwhMU06CmJoIDpF5 .rough-node .label text,#mermaid-svg-xwhMU06CmJoIDpF5 .node .label text,#mermaid-svg-xwhMU06CmJoIDpF5 .image-shape .label,#mermaid-svg-xwhMU06CmJoIDpF5 .icon-shape .label{text-anchor:middle;}#mermaid-svg-xwhMU06CmJoIDpF5 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-xwhMU06CmJoIDpF5 .rough-node .label,#mermaid-svg-xwhMU06CmJoIDpF5 .node .label,#mermaid-svg-xwhMU06CmJoIDpF5 .image-shape .label,#mermaid-svg-xwhMU06CmJoIDpF5 .icon-shape .label{text-align:center;}#mermaid-svg-xwhMU06CmJoIDpF5 .node.clickable{cursor:pointer;}#mermaid-svg-xwhMU06CmJoIDpF5 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-xwhMU06CmJoIDpF5 .arrowheadPath{fill:#333333;}#mermaid-svg-xwhMU06CmJoIDpF5 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-xwhMU06CmJoIDpF5 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-xwhMU06CmJoIDpF5 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-xwhMU06CmJoIDpF5 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-xwhMU06CmJoIDpF5 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-xwhMU06CmJoIDpF5 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-xwhMU06CmJoIDpF5 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-xwhMU06CmJoIDpF5 .cluster text{fill:#333;}#mermaid-svg-xwhMU06CmJoIDpF5 .cluster span{color:#333;}#mermaid-svg-xwhMU06CmJoIDpF5 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-xwhMU06CmJoIDpF5 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-xwhMU06CmJoIDpF5 rect.text{fill:none;stroke-width:0;}#mermaid-svg-xwhMU06CmJoIDpF5 .icon-shape,#mermaid-svg-xwhMU06CmJoIDpF5 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-xwhMU06CmJoIDpF5 .icon-shape p,#mermaid-svg-xwhMU06CmJoIDpF5 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-xwhMU06CmJoIDpF5 .icon-shape .label rect,#mermaid-svg-xwhMU06CmJoIDpF5 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-xwhMU06CmJoIDpF5 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-xwhMU06CmJoIDpF5 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-xwhMU06CmJoIDpF5 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} HTTP 请求
CorsFilter
LogFilter
AuthFilter
RateLimitFilter
Controller

过滤器通过 doFilter 决定是否继续向后传递。

java 复制代码
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
    // 前置处理
    chain.doFilter(request, response);
    // 后置处理
}

如果某个过滤器发现请求不合法,可以直接返回,不再调用后续链路。
#mermaid-svg-oQPgpii2IM20aHNQ{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-oQPgpii2IM20aHNQ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-oQPgpii2IM20aHNQ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-oQPgpii2IM20aHNQ .error-icon{fill:#552222;}#mermaid-svg-oQPgpii2IM20aHNQ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-oQPgpii2IM20aHNQ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-oQPgpii2IM20aHNQ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-oQPgpii2IM20aHNQ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-oQPgpii2IM20aHNQ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-oQPgpii2IM20aHNQ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-oQPgpii2IM20aHNQ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-oQPgpii2IM20aHNQ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-oQPgpii2IM20aHNQ .marker.cross{stroke:#333333;}#mermaid-svg-oQPgpii2IM20aHNQ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-oQPgpii2IM20aHNQ p{margin:0;}#mermaid-svg-oQPgpii2IM20aHNQ .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-oQPgpii2IM20aHNQ .cluster-label text{fill:#333;}#mermaid-svg-oQPgpii2IM20aHNQ .cluster-label span{color:#333;}#mermaid-svg-oQPgpii2IM20aHNQ .cluster-label span p{background-color:transparent;}#mermaid-svg-oQPgpii2IM20aHNQ .label text,#mermaid-svg-oQPgpii2IM20aHNQ span{fill:#333;color:#333;}#mermaid-svg-oQPgpii2IM20aHNQ .node rect,#mermaid-svg-oQPgpii2IM20aHNQ .node circle,#mermaid-svg-oQPgpii2IM20aHNQ .node ellipse,#mermaid-svg-oQPgpii2IM20aHNQ .node polygon,#mermaid-svg-oQPgpii2IM20aHNQ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-oQPgpii2IM20aHNQ .rough-node .label text,#mermaid-svg-oQPgpii2IM20aHNQ .node .label text,#mermaid-svg-oQPgpii2IM20aHNQ .image-shape .label,#mermaid-svg-oQPgpii2IM20aHNQ .icon-shape .label{text-anchor:middle;}#mermaid-svg-oQPgpii2IM20aHNQ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-oQPgpii2IM20aHNQ .rough-node .label,#mermaid-svg-oQPgpii2IM20aHNQ .node .label,#mermaid-svg-oQPgpii2IM20aHNQ .image-shape .label,#mermaid-svg-oQPgpii2IM20aHNQ .icon-shape .label{text-align:center;}#mermaid-svg-oQPgpii2IM20aHNQ .node.clickable{cursor:pointer;}#mermaid-svg-oQPgpii2IM20aHNQ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-oQPgpii2IM20aHNQ .arrowheadPath{fill:#333333;}#mermaid-svg-oQPgpii2IM20aHNQ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-oQPgpii2IM20aHNQ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-oQPgpii2IM20aHNQ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-oQPgpii2IM20aHNQ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-oQPgpii2IM20aHNQ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-oQPgpii2IM20aHNQ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-oQPgpii2IM20aHNQ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-oQPgpii2IM20aHNQ .cluster text{fill:#333;}#mermaid-svg-oQPgpii2IM20aHNQ .cluster span{color:#333;}#mermaid-svg-oQPgpii2IM20aHNQ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-oQPgpii2IM20aHNQ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-oQPgpii2IM20aHNQ rect.text{fill:none;stroke-width:0;}#mermaid-svg-oQPgpii2IM20aHNQ .icon-shape,#mermaid-svg-oQPgpii2IM20aHNQ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-oQPgpii2IM20aHNQ .icon-shape p,#mermaid-svg-oQPgpii2IM20aHNQ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-oQPgpii2IM20aHNQ .icon-shape .label rect,#mermaid-svg-oQPgpii2IM20aHNQ .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-oQPgpii2IM20aHNQ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-oQPgpii2IM20aHNQ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-oQPgpii2IM20aHNQ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 通过
不通过
请求进入过滤器
校验是否通过
调用下一个过滤器
直接返回错误响应

这就是责任链的典型特征:请求沿链传递,但每个节点都有机会处理、拦截或继续传递。

责任链适合哪些业务

场景 链路节点
订单创建 参数校验、补充数据、算价、落库、返佣
内容审核 文本审核、图片审核、视频审核、人工复核
审批流 组长、主管、总监、负责人
Web 过滤器 日志、鉴权、限流、跨域
风控校验 黑名单、频控、设备风险、地理位置风险

#mermaid-svg-qyaEw16Oxm2d8RY2{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-qyaEw16Oxm2d8RY2 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-qyaEw16Oxm2d8RY2 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-qyaEw16Oxm2d8RY2 .error-icon{fill:#552222;}#mermaid-svg-qyaEw16Oxm2d8RY2 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-qyaEw16Oxm2d8RY2 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-qyaEw16Oxm2d8RY2 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-qyaEw16Oxm2d8RY2 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-qyaEw16Oxm2d8RY2 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-qyaEw16Oxm2d8RY2 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-qyaEw16Oxm2d8RY2 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-qyaEw16Oxm2d8RY2 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-qyaEw16Oxm2d8RY2 .marker.cross{stroke:#333333;}#mermaid-svg-qyaEw16Oxm2d8RY2 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-qyaEw16Oxm2d8RY2 p{margin:0;}#mermaid-svg-qyaEw16Oxm2d8RY2 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-qyaEw16Oxm2d8RY2 .cluster-label text{fill:#333;}#mermaid-svg-qyaEw16Oxm2d8RY2 .cluster-label span{color:#333;}#mermaid-svg-qyaEw16Oxm2d8RY2 .cluster-label span p{background-color:transparent;}#mermaid-svg-qyaEw16Oxm2d8RY2 .label text,#mermaid-svg-qyaEw16Oxm2d8RY2 span{fill:#333;color:#333;}#mermaid-svg-qyaEw16Oxm2d8RY2 .node rect,#mermaid-svg-qyaEw16Oxm2d8RY2 .node circle,#mermaid-svg-qyaEw16Oxm2d8RY2 .node ellipse,#mermaid-svg-qyaEw16Oxm2d8RY2 .node polygon,#mermaid-svg-qyaEw16Oxm2d8RY2 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-qyaEw16Oxm2d8RY2 .rough-node .label text,#mermaid-svg-qyaEw16Oxm2d8RY2 .node .label text,#mermaid-svg-qyaEw16Oxm2d8RY2 .image-shape .label,#mermaid-svg-qyaEw16Oxm2d8RY2 .icon-shape .label{text-anchor:middle;}#mermaid-svg-qyaEw16Oxm2d8RY2 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-qyaEw16Oxm2d8RY2 .rough-node .label,#mermaid-svg-qyaEw16Oxm2d8RY2 .node .label,#mermaid-svg-qyaEw16Oxm2d8RY2 .image-shape .label,#mermaid-svg-qyaEw16Oxm2d8RY2 .icon-shape .label{text-align:center;}#mermaid-svg-qyaEw16Oxm2d8RY2 .node.clickable{cursor:pointer;}#mermaid-svg-qyaEw16Oxm2d8RY2 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-qyaEw16Oxm2d8RY2 .arrowheadPath{fill:#333333;}#mermaid-svg-qyaEw16Oxm2d8RY2 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-qyaEw16Oxm2d8RY2 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-qyaEw16Oxm2d8RY2 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-qyaEw16Oxm2d8RY2 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-qyaEw16Oxm2d8RY2 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-qyaEw16Oxm2d8RY2 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-qyaEw16Oxm2d8RY2 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-qyaEw16Oxm2d8RY2 .cluster text{fill:#333;}#mermaid-svg-qyaEw16Oxm2d8RY2 .cluster span{color:#333;}#mermaid-svg-qyaEw16Oxm2d8RY2 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-qyaEw16Oxm2d8RY2 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-qyaEw16Oxm2d8RY2 rect.text{fill:none;stroke-width:0;}#mermaid-svg-qyaEw16Oxm2d8RY2 .icon-shape,#mermaid-svg-qyaEw16Oxm2d8RY2 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-qyaEw16Oxm2d8RY2 .icon-shape p,#mermaid-svg-qyaEw16Oxm2d8RY2 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-qyaEw16Oxm2d8RY2 .icon-shape .label rect,#mermaid-svg-qyaEw16Oxm2d8RY2 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-qyaEw16Oxm2d8RY2 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-qyaEw16Oxm2d8RY2 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-qyaEw16Oxm2d8RY2 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是

业务请求
处理器 1
处理器 2
处理器 3
是否需要继续
处理器 4
提前结束

常见坑

坑一:链路太长

链路太长会导致一次请求经过很多对象,性能和可读性都会下降。责任链不是越长越好。

坑二:链路顺序不清晰

责任链对顺序敏感。先算价再填充订单,结果可能就是错的。链路顺序最好配置化或集中组装,别散落在各处。

坑三:节点没有明确职责

如果一个处理器里既校验参数,又查库存,又写日志,它就不是一个清晰节点。责任链要求节点职责边界清楚。

坑四:出现循环调用

如果链路配置错误,可能出现 A 调 B,B 又调回 A。生产代码里可以在链路构建阶段做校验,避免循环。
#mermaid-svg-HB0Lb1Nq6GE2KCfN{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-HB0Lb1Nq6GE2KCfN .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-HB0Lb1Nq6GE2KCfN .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-HB0Lb1Nq6GE2KCfN .error-icon{fill:#552222;}#mermaid-svg-HB0Lb1Nq6GE2KCfN .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-HB0Lb1Nq6GE2KCfN .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-HB0Lb1Nq6GE2KCfN .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-HB0Lb1Nq6GE2KCfN .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-HB0Lb1Nq6GE2KCfN .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-HB0Lb1Nq6GE2KCfN .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-HB0Lb1Nq6GE2KCfN .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-HB0Lb1Nq6GE2KCfN .marker{fill:#333333;stroke:#333333;}#mermaid-svg-HB0Lb1Nq6GE2KCfN .marker.cross{stroke:#333333;}#mermaid-svg-HB0Lb1Nq6GE2KCfN svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-HB0Lb1Nq6GE2KCfN p{margin:0;}#mermaid-svg-HB0Lb1Nq6GE2KCfN .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-HB0Lb1Nq6GE2KCfN .cluster-label text{fill:#333;}#mermaid-svg-HB0Lb1Nq6GE2KCfN .cluster-label span{color:#333;}#mermaid-svg-HB0Lb1Nq6GE2KCfN .cluster-label span p{background-color:transparent;}#mermaid-svg-HB0Lb1Nq6GE2KCfN .label text,#mermaid-svg-HB0Lb1Nq6GE2KCfN span{fill:#333;color:#333;}#mermaid-svg-HB0Lb1Nq6GE2KCfN .node rect,#mermaid-svg-HB0Lb1Nq6GE2KCfN .node circle,#mermaid-svg-HB0Lb1Nq6GE2KCfN .node ellipse,#mermaid-svg-HB0Lb1Nq6GE2KCfN .node polygon,#mermaid-svg-HB0Lb1Nq6GE2KCfN .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-HB0Lb1Nq6GE2KCfN .rough-node .label text,#mermaid-svg-HB0Lb1Nq6GE2KCfN .node .label text,#mermaid-svg-HB0Lb1Nq6GE2KCfN .image-shape .label,#mermaid-svg-HB0Lb1Nq6GE2KCfN .icon-shape .label{text-anchor:middle;}#mermaid-svg-HB0Lb1Nq6GE2KCfN .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-HB0Lb1Nq6GE2KCfN .rough-node .label,#mermaid-svg-HB0Lb1Nq6GE2KCfN .node .label,#mermaid-svg-HB0Lb1Nq6GE2KCfN .image-shape .label,#mermaid-svg-HB0Lb1Nq6GE2KCfN .icon-shape .label{text-align:center;}#mermaid-svg-HB0Lb1Nq6GE2KCfN .node.clickable{cursor:pointer;}#mermaid-svg-HB0Lb1Nq6GE2KCfN .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-HB0Lb1Nq6GE2KCfN .arrowheadPath{fill:#333333;}#mermaid-svg-HB0Lb1Nq6GE2KCfN .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-HB0Lb1Nq6GE2KCfN .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-HB0Lb1Nq6GE2KCfN .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-HB0Lb1Nq6GE2KCfN .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-HB0Lb1Nq6GE2KCfN .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-HB0Lb1Nq6GE2KCfN .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-HB0Lb1Nq6GE2KCfN .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-HB0Lb1Nq6GE2KCfN .cluster text{fill:#333;}#mermaid-svg-HB0Lb1Nq6GE2KCfN .cluster span{color:#333;}#mermaid-svg-HB0Lb1Nq6GE2KCfN div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-HB0Lb1Nq6GE2KCfN .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-HB0Lb1Nq6GE2KCfN rect.text{fill:none;stroke-width:0;}#mermaid-svg-HB0Lb1Nq6GE2KCfN .icon-shape,#mermaid-svg-HB0Lb1Nq6GE2KCfN .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-HB0Lb1Nq6GE2KCfN .icon-shape p,#mermaid-svg-HB0Lb1Nq6GE2KCfN .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-HB0Lb1Nq6GE2KCfN .icon-shape .label rect,#mermaid-svg-HB0Lb1Nq6GE2KCfN .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-HB0Lb1Nq6GE2KCfN .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-HB0Lb1Nq6GE2KCfN .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-HB0Lb1Nq6GE2KCfN :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 责任链设计
职责单一
顺序明确
可插拔扩展
避免循环
控制链路长度

面试怎么说

可以这样回答:

我在订单创建和请求过滤这类场景里用过责任链模式。责任链会把多个处理步骤拆成独立处理器,每个处理器只负责自己的逻辑,并持有下一个处理器引用。请求从链头开始传递,节点处理完后决定继续向后传,还是直接结束。它的好处是降低请求发送者和多个处理节点之间的耦合,新增步骤时可以新增处理器并调整链路顺序。但要注意链路不能太长,顺序要明确,也要避免配置错误导致循环调用。

小结

责任链模式最适合回答"多个处理步骤怎么优雅组织"。

可以这样记:

策略模式解决多选一,责任链模式解决按顺序过多关。

当一个请求天然要经过多个关卡,而且这些关卡还可能增减调整时,责任链就很适合。

相关推荐
许彰午12 小时前
责任链模式实战——同一个框架里的两种链
java·开发语言·责任链模式
逢君学术论文AI写作15 小时前
Java第22课:Servlet获取请求参数+POST请求+表单交互
java·servlet·ai写作
逢君学术论文AI写作15 小时前
Java第21课:JavaWeb入门——Tomcat+第一个Servlet
java·servlet·tomcat
就叫_这个吧15 小时前
Java使用tomcat+servlet+filter实现简单的登录功能,需先登录再进行页面数据管理操作
java·开发语言·servlet·tomcat·jsp·filter
wangyadong3172 天前
rancher 安装jenkins 。国内镜像太头疼
servlet·jenkins·rancher
就叫_这个吧4 天前
IDEA中Javaweb项目创建+servlet,实现简单的信息录入获取
java·servlet·intellij-idea·web
就叫_这个吧4 天前
servlet整合tomcat项目启动报错解决,org.apache.tomcat.util.descriptor.web.WebXml.setVersion
java·servlet·tomcat·apache
江华森4 天前
Jenkins CI/CD 实战博客教程
servlet·ci/cd·jenkins
Volunteer Technology5 天前
SpringSecurity中的权限管理
java·数据库·servlet