责任链模式之模仿Sentinel实现

时间:2024-04-09 09:06:11

在实际的项目生产活动中,我们经常会有很多前置处理,以及后置处理的需求。例如就拿简单的支付过程来说。
之前我们可能需要经过如下的环节:

  1. 根据支付请求,查询订单实际信息
  2. 根据实际订单信息,我们需要报送风控信息
  3. 查询优惠信息,进行优惠鉴权操作

以上就是可能出现的流程环节。那实际生产过程中,我们应该考虑用什么样的方式更合理的完成呢?
如果大家有阅读源码的习惯,其实可以在各种各样的开源框架中发现这种需求的存在。
比如 Spring的filter,Sentinel的限流操作,还有netty的pipline
这就是我们今天要说的责任链模式

责任链模式

定义:创建多个对象,使这些对象形成一条链,并沿着这条链传递请求,直到链上的某一个对象决定处理此请求。
特点:

  1. 接受请求的对象连接成一条链,对象之间存在层级关系
  2. 这些对象可以处理这些请求,也可以传递请求
    责任链模式之模仿Sentinel实现

实战练习

接下来就来实现一下开头说的支付前流程,通过看Sentinel 源码,实现的责任链模式。

基本类图

责任链模式之模仿Sentinel实现

ProcessorSolt

顶层节点类,该类定义了当前节点的行为,process 处理业务逻辑 ,fireProcess 触发下一个节点

public interface ProcessorSolt<T> {

    /**
     * 前置处理方法
     */
    void process(T param);

    /**
     * 触发下一个
     * @param param
     */
    void fireProcess(T param);
}

AbstractLinkedProcessorSlot

抽象类,链条节点类,顾名思义,该类维护了一个节点的下级关系
其中复写了process方法,运用模版模式,让链条上的点专注于节点的业务逻辑,而不用关注怎么触发下一个节点的。(PS:Sentinel源码中,是每个Slot手动触发下游节点的)

public abstract class AbstractLinkedProcessorSlot<T> implements ProcessorSolt<T> {

    /**
     * 设置链的下一个触发的组件
     */
    private AbstractLinkedProcessorSlot<T> next = null;

    @Override
    public void fireProcess(T param) {
        if(next != null){
            //触发下一个节点执行
            next.process(param);
        }
    }

    public AbstractLinkedProcessorSlot<T> getNext() {
        return next;
    }

    public void setNext(AbstractLinkedProcessorSlot<T> next) {
        this.next = next;
    }

    @Override
    public void process(T param) {

        processHandler(param);
        //触发下一个节点进行
        fireProcess(param);

    }

    /**
     * 定义钩子,是业务逻辑实际处理的实现
     * @param param
     */
    public abstract void processHandler(T param);
}

ProcessorSlotChain

该类继承AbstractLinkedProcessorSlot同时,新增了一个addLast方法,帮助开发人员构建我们链式节点。

public abstract class ProcessorSlotChain<T> extends AbstractLinkedProcessorSlot<T> {


    /**
     * 添加到下一个触发节点
     * @param processorSlot
     */
    public abstract void addLast(AbstractLinkedProcessorSlot<T> processorSlot);
}

DefaultProcessorSlotChain

责任链的具体实现类,关键点在于初始化了一个头节点,用于触发整个链条的向下进行

public class DefaultProcessorSlotChain<T> extends ProcessorSlotChain<T> {

    //初始化头检点
    AbstractLinkedProcessorSlot<T> first = new AbstractLinkedProcessorSlot<T>() {
        @Override
        public void processHandler(T param) {
            //不做处理
        }
    };

    AbstractLinkedProcessorSlot<T> end = first;


    @Override
    public void processHandler(T param) {
        //初始化头节点
        setNext(first);
    }

    @Override
    public void addLast(AbstractLinkedProcessorSlot<T> processorSlot) {
        //设置下一个节点
        end.setNext(processorSlot);
        //指针就指向下一个节点
        end = processorSlot;
    }
}

以上实现就是最主要的类,当然还包括其他的一些类

  1. SlotChainBuilder 构建类
  2. BeforeSlotChainBuilderImpl< ProcessorSlotChain> 构建实现类
public class BeforeSlotChainBuilderImpl implements SlotChainBuilder<ProcessorSlotChain> {



    @Override
    public ProcessorSlotChain build() {

        ProcessorSlotChain processorSlotChain = new DefaultProcessorSlotChain();

        processorSlotChain.addLast(new OrderInfoSlot());
        processorSlotChain.addLast(new RiskSlot());
        processorSlotChain.addLast(new MarketingSlot());

        return processorSlotChain;
    }
}

测试
@Slf4j
public class Test {

    public static void main(String[] args) {
        //新建一个支付前责任链
        BeforeSlotChainBuilderImpl beforeSlotChainBuilder = new BeforeSlotChainBuilderImpl();

        PaymentContext context = new PaymentContext();
        beforeSlotChainBuilder.build().process(context);

        log.info(context.toString());

    }
}

测试结果如图所示
责任链模式之模仿Sentinel实现
源码参考: https://github.com/zzjmay123/springboot-votes.git
在目录chain下