首页 > 其他分享 >聊聊如何实现一个特别的责任链

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

时间:2024-10-15 09:23:05浏览次数:6  
标签:pipeline Valve context void valve 责任 如何 聊聊 public

前言

什么是责任链

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

责任链的常用场景

  • 权限与认证系统:在登录认证、权限验证流程中,不同的处理者可以检查用户名密码、验证权限级别、处理单点登录等。请求(如访问资源)沿着责任链传递,直到找到合适的处理器来授权或拒绝访问。
  • 日志记录与错误处理:根据日志级别(如DEBUG, INFO, WARNING,
    ERROR)或错误类型,不同的处理器负责记录或处理相应的日志信息或异常。开发者可以灵活地插入或移除处理逻辑,而不影响其他日志处理。
  • 请求过滤与处理:在Web服务或API网关中,责任链可用于实现一系列预处理任务,如参数校验、请求限流、IP黑名单过滤、会话管理等,每个处理环节关注于特定的验证或转换逻辑。
  • 命令与事件处理:在处理一系列可选的或有顺序依赖的命令或事件时,责任链允许按照预定的逻辑顺序尝试执行处理逻辑,直到命令被执行或事件被妥善处理。
  • 工作流与审批流程:在企业应用中,审批流程可以设计成责任链,每个节点代表一个审批层级或角色,请求(如报销单)依次经过各个审批节点,直至最终批准或拒绝。
  • UI事件处理:在图形界面应用程序中,事件(如鼠标点击、键盘输入)可以通过责任链分发给不同的组件,每个组件决定是否消费此事件,未处理的事件继续传递给链中的下一个组件。

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

  • 每个Pipeline都是有特定的Valve,而且是在管道的最后一个执行,这个Valve叫BaseValve,并且BaseValve是不可删除的;
  • 在上层容器的管道的BaseValve中会调用下层容器的管道。

示例图:

如何实现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());
    }
}

总结

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

demo链接

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

标签:pipeline,Valve,context,void,valve,责任,如何,聊聊,public
From: https://www.cnblogs.com/linyb-geek/p/18172478

相关文章

  • 游戏《黑神话:悟空》突然崩溃:如何有效解决游戏黑神话悟空的AkFlanger.dll错误
    一、前言《黑神话:悟空》以其惊人的画面品质、精彩的剧情和深度的玩法,成为了众多玩家期待的游戏大作。然而,当玩家们沉浸在这个神秘的神话世界中时,游戏突然崩溃并出现AkFlanger.dll错误,这无疑会让人感到非常沮丧。那么,我们该如何有效解决这个问题呢?二、了解AkFlanger.dll......
  • 用python、JavaScript、JAVA等多种语言的实例代码演示教你如何免费获取股票数据(实时数
    ​近一两年来,股票量化分析逐渐受到广泛关注。而作为这一领域的初学者,首先需要面对的挑战就是如何获取全面且准确的股票数据。因为无论是实时交易数据、历史交易记录、财务数据还是基本面信息,这些数据都是我们进行量化分析时不可或缺的宝贵资源。我们的核心任务是从这些数据......
  • 请问如何修改网站内容
    要修改网站的内容,通常有几种方法,具体取决于网站的技术栈和你的访问权限。下面是一些常见的方法:直接编辑源文件:如果你有对服务器上网站文件的直接访问权限(例如通过FTP/SFTP或直接在服务器上操作),可以直接编辑HTML、CSS、JavaScript等文件来修改内容。使用CMS(内容管理系统):......
  • 如何进入网站后台管理页面
    进入网站后台管理页面通常涉及以下几个步骤:获取访问地址:了解网站后台的访问路径,通常是域名后面加上特定的路径,如 /admin 或 /wp-admin 等。登录凭证:拥有有效的用户名和密码。这些信息通常在网站建立之初就已设定好,或由网站管理员分配。访问后台:在浏览器中输......
  • 如何给自己的公司建网站
    为自己的公司建立一个网站可以分为几个基本步骤来完成:确定目标与需求:首先明确网站的主要功能和目标用户群体。是为了展示产品和服务,还是为了在线销售?或者是提供技术支持?选择域名:一个好的域名应该简单易记,并且最好能反映公司的业务或品牌名称。购买域名可以通过各大域名注册......
  • 如何修改自己网站的域名
    修改网站的域名通常涉及以下几个步骤:购买新域名:在域名注册商处购买您想要的新域名。更新DNS设置:登录到您的域名注册商或托管服务提供商的控制面板。修改DNS记录,将新的域名指向您网站的服务器IP地址或CDN地址。更新网站配置:如果您的网站使用的是CMS系统(如WordPre......
  • 公司网站如何更改内容
    要更改公司网站的内容,通常可以按照以下步骤操作:登录网站后台:首先,你需要登录到网站的内容管理系统(CMS)后台。这通常需要一个用户名和密码。选择编辑页面:在后台管理界面中找到你想要修改的页面或内容模块,并进入编辑模式。修改内容:根据需求修改文本、图片或其他媒体内容。大......
  • 如何通过网站后台修改网站怎样修改网站
    要通过网站后台修改网站内容或设置,通常可以遵循以下步骤:登录后台:打开网站的管理后台URL。输入管理员用户名和密码进行登录。导航到编辑页面:在后台界面中找到需要修改的部分,如文章、页面、产品列表等。选择“编辑”或相应的操作按钮进入具体编辑页面。进行内容编......
  • 如何保存修改过的网页源代码
    要保存修改过的网页源代码,可以按照以下步骤操作:选择保存方式:如果只是临时修改查看,可以直接在浏览器开发者工具中进行,但这些修改不会被持久化。若要永久保存修改后的源代码,则需要将其另存为本地文件。获取源代码:使用浏览器的“查看页面源代码”功能(通常可以通过右键菜......
  • 如何修改网站后台密码怎么修改网站密码
    修改网站后台密码通常涉及以下几个步骤:登录后台:使用当前的用户名和密码登录到网站的管理后台。找到用户设置:在后台界面中找到“用户”、“管理员”或“账号设置”等相关选项。进入密码修改页面:在用户设置中找到“修改密码”或类似功能的链接或按钮。输入新密......