聊聊如何实现一个特别的责任链

2024-10-14  本文已影响0人  linyb极客之路

前言

什么是责任链

责任链是一种设计模式,它让多个对象有机会处理同一个请求,这些对象形成一个链。请求从链的一端开始,逐个传递给链上的对象,直到某个对象处理它或者请求未被处理。这样,发送请求者无需知道哪个对象会处理,实现了发送者与接收者的解耦,增加了系统的灵活性

责任链的常用场景

今天给大家的介绍的责任链有点特殊,它是基于Pipeline-Valve模型,这种模型跟常规的责任链模式有点区别

示例图:

ade76302cbfbe1d5da6e65b1bcb0e194_cb210ea701e6ba81adb4dbae15d6f022.png

如何实现Pipeline-Valve模型

1、定义Valve接口

该接口表示处理链中的单个处理单元。

public interface Valve extends Ordered {

    Valve getNextValve();

    void setNextValve(Valve next);

    void invoke(ValveContext context);

    default boolean isBaiscValve() {
        return false;
    }


}

2、定义抽象valve(可选)

注:定义该抽象valve主要是为了复用

public abstract class AbstractValve implements Valve {

    protected Valve nextValve;

    @Override
    public Valve getNextValve() {
        return nextValve;
    }

    @Override
    public void setNextValve(Valve next) {
       this.nextValve = next;
    }

    @Override
    public void invoke(ValveContext context) {
         doInvoke(context);
         if(nextValve!=null){
             nextValve.invoke(context);
         }
    }

    public abstract void doInvoke(ValveContext context);


}

3、 定义Pipeline接口

该接口主要用来用于管理Valve的集合,并提供方法来添加Valve、设置特定valve以及启动处理流程。

public interface Pipeline {

    void setBasic(Valve valve);

    void addValve(Valve valve);

    void process(ValveContext context);
}

4、定义Pipeline的默认实现

public class StandardPipeline implements Pipeline {
    /**
     * 第一个阀门
     */
    protected Valve first;

    /**
     * 最后一个阀门
     */
    protected Valve basic;


    @Override
    public void setBasic(Valve valve) {
        validateValve(valve,true);
        this.basic = valve;
    }

    @Override
    public void addValve(Valve valve) {
        validateValve(valve,false);
        if(first == null){
            this.first = valve;
            valve.setNextValve(basic);
        }else{
            Valve current = first;
            while(current != null){
               if(current.getNextValve() == basic){
                   current.setNextValve(valve);
                   valve.setNextValve(basic);
                   break;
               }
               current = current.getNextValve();
            }
        }

    }

    @Override
    public void process(ValveContext context) {
        if(first != null){
            if(context == null){
                context = new ValveContext();
            }
            first.invoke(context);
        }

    }

    public void validateValve(Valve valve,boolean isCheckBasicValve){
        Assert.notNull(valve, "valve must not be null");
        if(isCheckBasicValve){
            Assert.isTrue(valve.isBaiscValve(), "valve must be basic valve");
        }
    }
}

注: addValue else流程,是为了保证basic阀门一定是在流程最后被调用

5、定义具体valve

@Component
public class FirstValve extends AbstractValve {
    @Override
    public void doInvoke(ValveContext context) {
        String requestId = "lybgeek-" + UUID.randomUUID().toString();
        System.out.println("第一道阀门: requestId-->【" + requestId + "】");
        Map<String,Object> request = context.getRequest();
        request.put("source",FirstValve.class.getSimpleName());
        context.setRequest(request);
        context.setRequestId(requestId);
    }

    @Override
    public int getOrder() {
        return 1;
    }
}



其他阀门类似,就不列举了

6、通过Pipeline 驱动valve

public class PipelineMainTest {

    public static void main(String[] args) {
        Pipeline pipeline = new StandardPipeline();
        pipeline.setBasic(new BasicValve());
        pipeline.addValve(new FirstValve());
        pipeline.addValve(new SecondValve());
        pipeline.addValve(new ThirdValve());
        pipeline.process(new ValveContext());
    }
}
2d98e815bd09b594c7e63bfb8c715419_d4c89d88640c5f67bbc8a88edd73a93b.png

总结

如果大家对tomcat有了解的话,就会知道本文的实现其实就是tomcat的pipeline-valve的简化版实现。其次上文pipeline驱动valve的步骤可以托管给spring,文末demo链接的代码,有做了相应实现,感兴趣的朋友,可以点击文末链接查看

demo链接

https://github.com/lyb-geek/springboot-learning/tree/master/springboot-pipeline-valve

上一篇 下一篇

猜你喜欢

热点阅读