责任链

背景

最近在写公司业务代码的时候用到了责任链模式,借这个机会回顾下责任链设计模式。

什么是责任链模式

责任链模式是一种行为设计模式,它允许你将请求沿着处理者链进行发送。当一个请求到达链的起始端时,它会依次经过每个处理者,直到有一个处理者能够处理该请求或者到达链的末端。以下是责任链模式的一些关键信息:

组成部分

  • 抽象处理者(Handler) :定义了一个处理请求的抽象方法,并持有一个指向下一个处理者的引用。
  • 具体处理者(Concrete Handler) :实现了抽象处理者的处理方法,在方法中判断是否能够处理请求,如果可以则处理,否则将请求传递给下一个处理者。
  • 客户端(Client) :创建处理者链,并向链的起始端发送请求。

示例代码

java 复制代码
// 抽象处理者
abstract class Handler {
    protected Handler successor;

    public void setSuccessor(Handler successor) {
        this.successor = successor;
    }

    public abstract void handleRequest(int request);
}

// 具体处理者1
class ConcreteHandler1 extends Handler {
    @Override
    public void handleRequest(int request) {
        if (request >= 0 && request < 10) {
            System.out.println("ConcreteHandler1 处理请求 " + request);
        } else if (successor != null) {
            successor.handleRequest(request);
        }
    }
}

// 具体处理者2
class ConcreteHandler2 extends Handler {
    @Override
    public void handleRequest(int request) {
        if (request >= 10 && request < 20) {
            System.out.println("ConcreteHandler2 处理请求 " + request);
        } else if (successor != null) {
            successor.handleRequest(request);
        }
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {
        Handler handler1 = new ConcreteHandler1();
        Handler handler2 = new ConcreteHandler2();

        handler1.setSuccessor(handler2);

        int[] requests = {5, 12, 18, 25};
        for (int request : requests) {
            handler1.handleRequest(request);
        }
    }
}

责任链设计模式 - 图示

整个图示就类似一个链表

责任链设计模式 - 审批案例

java 复制代码
// 定义处理者接口
abstract class Approver {
    protected Approver nextApprover;

    public void setNextApprover(Approver nextApprover) {
        this.nextApprover = nextApprover;
    }

    public abstract void approve(int days);
}

// 具体处理者:组长
class TeamLeader extends Approver {
    @Override
    public void approve(int days) {
        if (days <= 1) {
            System.out.println("组长批准了 " + days + " 天的请假申请。");
        } else if (nextApprover != null) {
            nextApprover.approve(days);
        }
    }
}

// 具体处理者:经理
class Manager extends Approver {
    @Override
    public void approve(int days) {
        if (days <= 3) {
            System.out.println("经理批准了 " + days + " 天的请假申请。");
        } else if (nextApprover != null) {
            nextApprover.approve(days);
        }
    }
}

// 具体处理者:总监
class Director extends Approver {
    @Override
    public void approve(int days) {
        if (days <= 7) {
            System.out.println("总监批准了 " + days + " 天的请假申请。");
        } else {
            System.out.println("请假天数超过 7 天,申请被拒绝。");
        }
    }
}

// 客户端代码
public class Main {
    public static void main(String[] args) {
        // 创建处理者
        Approver teamLeader = new TeamLeader();
        Approver manager = new Manager();
        Approver director = new Director();

        // 构建责任链
        teamLeader.setNextApprover(manager);
        manager.setNextApprover(director);

        // 发送请求
        teamLeader.approve(1);
        teamLeader.approve(3);
        teamLeader.approve(5);
        teamLeader.approve(10);
    }
}

运行结果:

这个案例还是挺简单的,接下来我们再看一个spring中拦截器的案例。

Spring 中的 Interceptor

代码

java 复制代码
// 自定义拦截器 1
@Component
public class FirstInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("FirstInterceptor: preHandle");
        // 返回false,不会走后面拦截器
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("FirstInterceptor: postHandle");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("FirstInterceptor: afterCompletion");
    }
}
java 复制代码
// 自定义拦截器 2
@Component
public class SecondInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("SecondInterceptor: preHandle");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("SecondInterceptor: postHandle");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("SecondInterceptor: afterCompletion");
    }
}
java 复制代码
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Autowired
    private FirstInterceptor firstInterceptor;
    @Autowired
    private SecondInterceptor secondInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // /** 表示拦截所有请求
        registry.addInterceptor(firstInterceptor).addPathPatterns("/**");
        registry.addInterceptor(secondInterceptor).addPathPatterns("/**");
    }
}

执行结果

Interceptor 结构

从上面的执行结果我们可以分析出,interceptor的责任链是双向的,顺序执行完再逆序执行,如下图所示结构

pre、post、aftercompletion

interceptor 责任链各个处理器是用List来接住的,所以方便的顺序执行和逆序执行。

HandlerExecutionChain 类

接下来再具体看看哪里调用的。

DispatcherServlet 类

DispatcherServlet中的doDispatcher方法

pre执行时机:

从这里我们可以看到,如果拦截器链里有一个pre方法返回false,那么后续的pre以及post和aftercompletion都不会再执行。

post执行时机:

aftercompletion执行时机:

如果报错了,那么会在catch里执行aftercompletion

所以总结下来拦截器链的pre,post,aftercompletion执行顺序是:

(1)责任链顺序执行pre,如果返回的都是true,继续下面步骤 (2)逆序执行post (3)逆序执行aftercompletion

总结

spring 中 interceptor 用的也是责任链模式,不过是更加复杂的责任链,依赖于List组成一个抽象的双向链表,这样方便对责任链进行顺序遍历和逆序遍历。

模仿拦截器中的责任链

代码

java 复制代码
// 订单类(保持不变)
class Order {
    private String orderId;
    private double amount;
    private int quantity;

    public Order(String orderId, double amount, int quantity) {
        this.orderId = orderId;
        this.amount = amount;
        this.quantity = quantity;
    }

    public String getOrderId() {
        return orderId;
    }

    public double getAmount() {
        return amount;
    }

    public int getQuantity() {
        return quantity;
    }

    public void setQuantity(int quantity) {
        this.quantity = quantity;
    }
}

// 处理器接口(移除setNextHandler)
interface OrderHandler {
    boolean preHandle(Order order);
    void postHandle(Order order);
    void afterCompletion(Order order, Exception ex);
}

// 订单验证处理器
class OrderValidatorHandler implements OrderHandler {
    @Override
    public boolean preHandle(Order order) {
        if (order.getAmount() <= 0 || order.getQuantity() <= 0) {
            System.out.println("订单验证失败:订单金额或数量无效。");
            return false;
        }
        System.out.println("订单验证通过。");
        return true; // 继续执行下一个处理器
    }

    @Override
    public void postHandle(Order order) {
        System.out.println("订单验证处理器:postHandle 操作完成。");
    }

    @Override
    public void afterCompletion(Order order, Exception ex) {
        System.out.println("订单验证处理器:afterCompletion 操作完成,异常信息:" + (ex != null ? ex.getMessage() : "无"));
    }
}

// 库存检查处理器
class InventoryCheckHandler implements OrderHandler {
    private int stock = 10;

    @Override
    public boolean preHandle(Order order) {
        if (order.getQuantity() > stock) {
            System.out.println("库存检查失败:库存不足。");
            return false;
        }
        System.out.println("库存检查通过。");
        stock -= order.getQuantity();
        return true;
    }

    @Override
    public void postHandle(Order order) {
        System.out.println("库存检查处理器:postHandle 操作完成。");
    }

    @Override
    public void afterCompletion(Order order, Exception ex) {
        System.out.println("库存检查处理器:afterCompletion 操作完成,异常信息:" + (ex != null ? ex.getMessage() : "无"));
    }
}

// 支付处理处理器
class PaymentHandler implements OrderHandler {
    @Override
    public boolean preHandle(Order order) {
        System.out.println("支付处理成功,支付金额:" + order.getAmount());
        return true;
    }

    @Override
    public void postHandle(Order order) {
        System.out.println("支付处理处理器:postHandle 操作完成。");
    }

    @Override
    public void afterCompletion(Order order, Exception ex) {
        System.out.println("支付处理处理器:afterCompletion 操作完成,异常信息:" + (ex != null ? ex.getMessage() : "无"));
    }
}

// 订单完成处理器
class OrderCompletionHandler implements OrderHandler {
    @Override
    public boolean preHandle(Order order) {
        System.out.println("订单 " + order.getOrderId() + " 处理完成。");
        return true;
    }

    @Override
    public void postHandle(Order order) {
        System.out.println("订单完成处理器:postHandle 操作完成。");
    }

    @Override
    public void afterCompletion(Order order, Exception ex) {
        System.out.println("订单完成处理器:afterCompletion 操作完成,异常信息:" + (ex != null ? ex.getMessage() : "无"));
    }
}

// 责任链构建器(改为维护处理器列表)
class OrderHandlerChainBuilder {
    private List<OrderHandler> handlers = new ArrayList<>();

    public OrderHandlerChainBuilder addHandler(OrderHandler handler) {
        handlers.add(handler);
        return this;
    }

    public List<OrderHandler> build() {
        return handlers;
    }
}

// 测试类
public class OrderChainTest {
    public static void main(String[] args) {
        // 创建处理器
        OrderValidatorHandler validator = new OrderValidatorHandler();
        InventoryCheckHandler inventoryCheck = new InventoryCheckHandler();
        PaymentHandler payment = new PaymentHandler();
        OrderCompletionHandler completion = new OrderCompletionHandler();

        // 构建责任链
        OrderHandlerChainBuilder builder = new OrderHandlerChainBuilder();
        List<OrderHandler> handlers = builder.addHandler(validator)
                .addHandler(inventoryCheck)
                .addHandler(payment)
                .addHandler(completion)
                .build();

        // 创建订单
        Order validOrder = new Order("123", 100.0, 5);
        Order invalidOrder = new Order("456", -10.0, 20);

        // 处理有效订单
        System.out.println("处理有效订单:");
        processOrder(validOrder, handlers);

        // 处理无效订单
        System.out.println("\n处理无效订单:");
        processOrder(invalidOrder, handlers);
    }

    private static void processOrder(Order order, List<OrderHandler> handlers) {
        List<OrderHandler> executedHandlers = new ArrayList<>();
        boolean processSuccess = true;
        Exception exception = null;

        // 按顺序执行preHandle
        for (OrderHandler handler : handlers) {
            boolean result = handler.preHandle(order);
            executedHandlers.add(handler);
            if (!result) {
                processSuccess = false;
                break;
            }
        }

        try {

            if (processSuccess) {
                // 如果全部preHandle成功,逆序执行postHandle
                for (int i = executedHandlers.size() - 1; i >= 0; i--) {
                    executedHandlers.get(i).postHandle(order);
                }

                // 如果全部preHandle成功,逆序执行afterCompletion
                for (int i = executedHandlers.size() - 1; i >= 0; i--) {
                    executedHandlers.get(i).afterCompletion(order, exception);
                }
            }
        } catch (Exception e) {
            exception = e;
        }



        System.out.println("订单处理结果:" + (processSuccess ? "成功" : "失败"));
    }
}

执行结果

总结

  1. 责任链设计模式可以抽象成一个链表来理解,单链表和双链表
  2. spring 中的interceptors 是 用List抽象的双链表
相关推荐
宁懿妤1 分钟前
Lua语言的网络编程
开发语言·后端·golang
南雨北斗4 分钟前
拒绝陌生域名解析到服务器
后端
卑微小文5 分钟前
国内P2P金融平台风险评估:代理IP提供全面数据支撑
后端
XW13 分钟前
个人图片分类-按照年分文件夹管理 python处理个人图片
后端
敖云岚15 分钟前
【Spring】第四弹:基于XML文件注入Bean对象
xml·java·spring
customer0830 分钟前
【开源免费】基于SpringBoot+Vue.JS电商应用系统(JAVA毕业设计)
java·vue.js·spring boot·后端·开源
Pandaconda31 分钟前
【后端开发面试题】每日 3 题(十五)
数据库·分布式·后端·python·面试·后端开发·幂等性
习惯就好zz32 分钟前
Kotlin标准函数库学习
java·学习·kotlin
rookiefishs1 小时前
如何nodejs中使用winston库记录本地日志?
前端·javascript·后端
知识分享小能手1 小时前
CSS3学习教程,从入门到精通,CSS3 选择器权重问题语法知识点及案例代码(5)
java·前端·css·学习·html·css3·html5