责任链模式在项目中的引入使用

2023-11-08

责任链模式是一种设计模式。在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。

 在Java中我觉得最为经典的属于,Servlet中的过滤器(Filter)和过滤器链(FilterChain)组合。

1.filter一般用于Servlet处理一些前置的校验,且给个filter有自己各自的责任和处理逻辑,在调用filter时候,需要传递filterChain,来告诉当前的执行的是那一个chain.

public interface Filter {

    
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException;

    public default void destroy() {}
}
public interface FilterChain {


    public void doFilter(ServletRequest request, ServletResponse response)
            throws IOException, ServletException;

}
/**
 * XSS过滤器  自定义的filter
 */
public class XSSFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void destroy() {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        // 调用下一个
        chain.doFilter(new XSSRequestWrapper((HttpServletRequest) request), response);
    }
}

大致处理流程:

 2. 这种链路叶跟pipeline管道模式有点像,在netty中我们在设置pipeline,也是按照这个规则去设置各种handler。在我自己的项目中我是按照这个Servlet的原型进行改造的。来实现项目中前置请求的一些校验工作。

 2.1:业务中有患者挂号业务,按照要求我们现有检查患者是否在医院有建档数据,没有t建档。否则还需要检查,当天是否重复挂号等。按照这个简化的需求业务我们来实现。

2.2: 基础的核心接口

public interface Filter {

    //处理逻辑,
    public void doFilter(FilterRequestDTO filterRequestDTO, FilterChain filterChain);


    public void reset();
}
public interface FilterChain {


    public void doFilter(FilterRequestDTO filterRequestDTO);

    void reset();
}
public class CouponFilterChain implements FilterChain {
    /**
     * 责任链中的所有的处理组件 非变量
     */
    private final List<? extends AbstractOrderFilter> filters;
    /**
     * 当前执行到的位置 这是个共享变量
     */
    private static ThreadLocal<Integer> posLocal = ThreadLocal.withInitial(() -> 0);

    /**
     * 责任链的校验结果--即需要给用户反馈的校验结果,共享变量,threadLocal,会作为全局参数
     */
    public static final ThreadLocal<List<CheckResult>> checkResult = new ThreadLocal<>();

    /**
     * 包含filter数量 非变量
     */
    private final int size;

    @Override
    public void doFilter(FilterRequestDTO filterRequestDTO) {
        //共享变量记住当前filterChain执行的filter的index,直至结束
        Integer pos = posLocal.get();
        if (pos < size) {
            pos++;
            posLocal.set(pos);
            Filter filter = this.filters.get(pos - 1);
            filter.doFilter(filterRequestDTO, this);
        }
    }

    //供外部业务代码调用的主要方法
    public List<CheckResult> process(FilterRequestDTO filterRequestDTO) {
        this.doFilter(filterRequestDTO);
        //将共享变量里面的结果取出来,返回给用户
        return checkResult.get();
    }

    //注意避免ThreadLocal内存泄漏,要remove
    @Override
    public void reset() {
        posLocal.remove();
        posLocal.set(0);
        checkResult.remove();
    }

    public CouponFilterChain(List<? extends AbstractOrderFilter> filters) {
        filters.sort(AbstractOrderFilter::compareTo);
        this.filters = filters;
        this.size = filters.size();
    }
}

定义抽象filter类


@Data
public class AbstractOrderFilter implements Filter, Comparable<AbstractOrderFilter> {

    //排序字段
    protected Integer order;

    @Override
    public int compareTo(AbstractOrderFilter abstractOrderFilter) {
        return getOrder().compareTo(abstractOrderFilter.getOrder());
    }

    /**
     * 接受
     * 根据Filter自己使用的业务场景,自行定义
     *
     * @param filterRequestDTO 过滤请求dto
     * @return boolean    返回值类型
     * @author 余浪
     */
    public boolean accept(FilterRequestDTO filterRequestDTO) {
        return true;
    }

    /**
     * 做过滤器
     *
     * @param filterRequestDTO 过滤请求dto
     * @param filterChain      过滤器链
     *                         返回值类型
     * @author 余浪
     */
    @Override
    public void doFilter(FilterRequestDTO filterRequestDTO, FilterChain filterChain) {

    }

    @Override
    public void reset() {

    }
}

定义两个业务filter

/**
 * 挂号 过滤器
 *
 * @author 余浪
 * @date 2023-06-14
 */
@Slf4j(topic = "checkRegisterFilter")
public class CheckRegisterFilter extends AbstractOrderFilter {


    private CheckRegisterService checkRegisterService;


    private CheckRegisterFilter(Integer order, CheckRegisterService checkRegisterService) {
        super.order = order;
        this.checkRegisterService = checkRegisterService;
    }

    @Override
    public void doFilter(FilterRequestDTO filterRequestDTO, FilterChain filterChain) {

        // 检查通过 在乎校验本次链路的逻辑
        if (accept(filterRequestDTO)) {
            //检查当前是否挂号
            Boolean flag = 
               checkRegisterService.checkPatientWhetherToRegister(filterRequestDTO);

            Assert.isTrue(flag,"当天重复挂号了");
        }
        //继续走责任链的下一个filter
        filterChain.doFilter(filterRequestDTO);
    }

    /**
     * 做自定义校验的 ,控制是否需要 执行当前链路的校验
     *
     * @param filterRequestDTO 过滤请求dto
     * @return boolean    返回值类型
     * @author 余浪
     */
    @Override
    public boolean accept(FilterRequestDTO filterRequestDTO) {
        //  检查患者id 可以做患者身份校验等
        if (StrUtil.isNotBlank(filterRequestDTO.getPatientId())) {

            log.info("身份信息合法。。。 ");

            return false;
        }
        log.info("身份信息非法 ");
        //自行根据业务场景定义处理何种请求
        return true;
    }

    //对外暴露的create方法
    public static CheckRegisterFilter create(Integer order, CheckRegisterService checkRegisterService) {
        return new CheckRegisterFilter(order, checkRegisterService);
    }
}

/**
 * 检查构建文件过滤器
 *
 * @author 余浪
 * @date 2023-06-14
 */
@Slf4j(topic = "checkBuildFileFilter")
public class CheckBuildFileFilter extends AbstractOrderFilter {

    //当前filter对应的业务逻辑manager(自行根据业务场景定义) 你自己的建档逻辑服务
    private BuildFileService buildFileService;


    private CheckBuildFileFilter(Integer order, BuildFileService buildFileService) {
        super.order = order;
        this.buildFileService = buildFileService;
    }

    @Override
    public void doFilter(FilterRequestDTO filterRequestDTO, FilterChain filterChain) {

        // 检查通过 在乎校验本次链路的逻辑
        if (accept(filterRequestDTO)) {
            //业务逻辑对应的manager进行校验处理(不做展开)
            Boolean patientExists =     
                  buildFileService.checkPatientExists(filterRequestDTO);

            if(!patientExists){
                throw new RuntimeException("用户未建档");
            }
        }
        //继续走责任链的下一个filter
        filterChain.doFilter(filterRequestDTO);
    }

    /**
     *  做自定义校验的 ,控制是否需要 执行当前链路的校验
     * @param filterRequestDTO 过滤请求dto
     * @return boolean    返回值类型
     * @author 余浪
     */
    @Override
    public boolean accept(FilterRequestDTO filterRequestDTO) {
        // 身份证合法 才会去建档 ,根据自己的具体业务实现
        if(StrUtil.isNotBlank(filterRequestDTO.getIdentityCardNumber())
                && IdcardUtil.isValidCard(filterRequestDTO.getIdentityCardNumber())){

            log.info("身份信息合法。。。 ");

            return false;
        }
        log.info("身份信息非法 ");
        //自行根据业务场景定义处理何种请求
        return true;
    }

    //对外暴露的create方法
    public static CheckBuildFileFilter create(Integer order, BuildFileService buildFileService) {
        return new CheckBuildFileFilter(order, buildFileService);
    }
}

2.3: 定义FilterChainManager

@Component
@Slf4j
public class CustomFilterChainManager {

    @Autowired
    private BuildFileService buildFileService;

    @Autowired
    private CheckRegisterService checkRegisterService;

    private CouponFilterChain couponFilterChain;

    //初始化责任链
    @PostConstruct
    private void init() {
        //总链
        List<AbstractOrderFilter> filters = new ArrayList<>();
        //按需添加链上的filter……
        //商品校验filter
        filters.add(CheckBuildFileFilter.create(300, buildFileService));
        //门店校验filter
        filters.add(CheckRegisterFilter.create(200, checkRegisterService));

        this.couponFilterChain = new CouponFilterChain(filters);
    }

    //供外部调用的方法
    public void process(FilterRequestDTO filterRequestDTO) {
        try {
            //责任链模式
           couponFilterChain.process(filterRequestDTO);
          
        } catch (Exception e) {
           
        } finally {
            //这里非常重要 必须重置
            if (couponFilterChain != null) {
                couponFilterChain.reset();
            }
        }
    }
}

测试:

    @Autowired
    private CustomFilterChainManager customFilterChainManager;

    @Test
    public void testDemo(){
        FilterRequestDTO filterRequestDTO = new FilterRequestDTO();
        // 身份证号
        filterRequestDTO.setIdentityCardNumber("123455");
        customFilterChainManager.process(filterRequestDTO);
    }

下一章节

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

责任链模式在项目中的引入使用 的相关文章

  • webpack进阶--01--环境变量的设置

    环境变量的设置 在用webpack作为打包工具的项目中 环境变量共有三种 node运行时的环境变量 webpack配置对象的环境变量 js运行时的环境变量 node运行时的环境变量 在node环境中 通过process env可以获取nod
  • 【Redux】通过示例和简化源码深入了解Redux原理

    createStore 作用 创建一个包含程序完整 state 树的 Redux store 应用中应有且仅有一个 store Store 就是用来维持应用所有的 state 树 的一个对象 改变 store 内 state 的惟一途径是对

随机推荐

  • 梯度下降算法3维图像示例

    import numpy as np import matplotlib pyplot as plt import matplotlib pylab as mpl from mpl toolkits mplot3d import Axes3
  • 华为MSTP负载均衡配置示例

    华为MSTP负载均衡配置示例 https www cnblogs com zhuimengle p 5906806 html MSTP负载均衡配置示例 本示例拓扑结构如图8 38所示 SwitchA SwitchB SwitchC和Swit
  • WEB-INF下的jsp不能访问的问题

    放在Tomcat WEB INF目录下的文件 image png 当浏览器访问Result jsp时 无法正常显示 通过了解才得知 原来Tomcat WEB INF目录下的文件 浏览器一般无法直接方法 只能通过重定向后才可以访问 如果需要直
  • 象棋对战js代码实现

    象棋对战js代码实现 思路 1 将棋盘设置为背景图片 对背景图片进行分割 分为9行10列的div块 每一块都是棋子的一个位置 2 对每一个div块设置onclick点击事件 每次点击div块都会调用判断棋子的走法是否合理的函数 pandua
  • Spark2.0特征提取、转换、选择之一:数据规范化,String-Index、离散-连续特征相互转换

    数据规范化 标准化 在数据预处理时 这两个术语可以互换使用 不考虑标准化在统计学中有特定的含义 下面所有的规范化操作都是针对一个特征向量 dataFrame中的一个colum 来操作的 首先举一个例子 MaxAbsScaler例子 参考后面
  • Unity基于C#事件委托机制

    事件委托是一种用于实现观察者模式的设计模式 它允许对象在发生特定事件时通知其他对象 在Unity中 事件委托机制为开发者提供了一种简单而有效的方式来处理游戏中的事件和交互 对啦 这里有个游戏开发交流小组里面聚集了一帮热爱学习游戏的零基础小白
  • python算术运算符

    运算符 描述 实例 加 1 1 2 减 3 2 1 乘 2 3 6 除 4 2 2 取整除 返回除法的整数部分 商 9 2 4 取余数 返回除法的余数 9 2 1 幂 又称次方 乘方 2 3 8 算术运算符的优先级 运算符 描述 幂 最高优
  • 区块链的优缺点

    区块链的优点 一是难以篡改 更加安全 在传统信息系统的安全方案中 安全依赖于层层设防的访问控制 通过区块链技术 记录交易的数据库任何人都可以访问 但由于巧妙的设计并辅以密码学和共识机制 区块链的数据记录方式使得修改某一数据需要变更所有的后续
  • TypeError: cannot unpack non-iterable NoneType object

    python报错如下 TypeError cannot unpack non iterable NoneType object 解决方法 报错的原因是函数返回值得数量不一致 查看函数返回值数量和调用函数时接收返回值的数量是不是一致 修改一致
  • Java出现"此时不应有......."的错误

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 今晚在安装weblogic的时候 双击运行startWebLogic cmd dos窗口一闪而过 随后将 startWebLogic cmd 拖进cmd窗口运行 显示 此时
  • Android 不同版本通过mk拷贝并安装APK

    目录 前景 解决思路 注意事项 Android 11 Android 9 前景 工作中 有时APK通过系统编译的方式包进系统会丢失so库或者lib包 导致APK无法正常运行 但手动安装就不会出现这个问题 解决思路 可以使用一个取巧的方式解决
  • 无桥PFC的家族推演

    1 组合法构建无桥PFC PFC是一种AC DC变换器 将交流输入电压分成正负半周 输出电压是直流 因此AC DC变换器可以当做是两个DC DC变换器的组合 在PFC的拓扑推演中 就是设计两个DC DC变换器的工作模式 以下内容是基于对陈正
  • 遗传编程(GA,genetic programming)算法初探,以及用遗传编程自动生成符合题解的正则表达式的实践...

    1 遗传编程简介 0x1 什么是遗传编程算法 和传统机器学习算法有什么区别 传统上 我们接触的机器学习算法 都是被设计为解决某一个某一类问题的确定性算法 对于这些机器学习算法来说 唯一的灵活性体现在参数搜索空间上 向算法输入样本 算法借助不
  • i2c-core module could not be probed怎么解决啊

    求大佬帮忙看看 root PandoraBox A983 lib modules 3 14 79 uname a Linux PandoraBox A983 3 14 79 0 SMP Sat Sep 7 12 52 27 2019 arm
  • postman GET请求传Java实体,实体中又有对象实体数组

    controller代码接收参数如下 GetMapping getList ApiOperation 获取列表 public Object getList SearchListParam searchListParam return nul
  • 使用 Docker 运行简单的 python 程序

    以下是一个简单的 python 程序 用户输入一个最小值和最大值 输出二者之间的随机数 from random import randint min number int input Please enter the min number
  • 利用chatgpt实现三分钟快速制作自定义PPT

    目录 利用ChatGPT MindShow三分钟生成PPT 机器人 道合顺 莓用ai 百晓生 aichat 结合提词器以达到更好地提问效果 更好地提问ChatGPT 常用prompt表 小黄同学LL的博客 CSDN博客 举个栗子 利用Cha
  • 现代循环神经网络-门控循环单元(GRU)

    理论 门控隐状态 门控循环单元与普通的循环神经网络之间的关键区别在于 前者支持隐状态的门控 这意味着模型有专门的机制来确定应该何时更新隐状态 以及应该何时重置隐状态 这些机制是可学习的 并且能够解决了上面列出的问题 例如 如果第一个词元非常
  • stream().sorted 排序

    想用stream sorted 做双字段排序 list stream sorted Comparator comparing outObject gt outObject getinnerObject getAttribute revers
  • 责任链模式在项目中的引入使用

    责任链模式是一种设计模式 在责任链模式里 很多对象由每一个对象对其下家的引用而连接起来形成一条链 请求在这个链上传递 直到链上的某一个对象决定处理此请求 发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求 这使得系统可以在不影响客