Spring + 设计模式 (十八) 行为型 - 责任链模式

责任链模式

引言

责任链模式是一种行为型设计模式,它将请求沿着处理链传递,直到有一个处理器处理它为止。每个处理器只关注自己职责范围内的事,其余交给链上的下一个处理器。这种结构的核心价值在于解耦请求的发送者与多个处理者之间的关系,让请求在"职责链"中动态传递,实现灵活、可插拔的处理机制。

实际开发中的用途

在实际开发中,责任链模式广泛用于过滤器链、权限校验、数据校验、日志处理、工作流编排等场景。当一个请求需要经过多个步骤或可能由多个处理器处理时,使用责任链模式可以避免臃肿的 if/else 或 switch-case 结构,使处理逻辑更加清晰、可扩展。例如:HTTP 请求过滤器链、订单审批流、用户输入校验流程等。

Spring源码中的应用

Spring 中责任链模式的典型体现是 Servlet Filter 链、HandlerInterceptor 链、BeanPostProcessor 链 等。在这些场景中,请求或Bean对象会依次经过多个处理器,直到链尾,体现了经典的责任链结构。

org.springframework.web.servlet.HandlerInterceptor 为例,Spring MVC 会在请求进入 Controller 前依次执行注册的拦截器:

java 复制代码
// DispatcherServlet.java
mappedHandler.applyPreHandle(processedRequest, response);

// HandlerExecutionChain.java
public boolean applyPreHandle(...) {
    for (int i = 0; i < interceptors.length; i++) {
        HandlerInterceptor interceptor = interceptors[i];
        if (!interceptor.preHandle(request, response, handler)) {
            // 中断责任链
            triggerAfterCompletion();
            return false;
        }
    }
    return true;
}

每个拦截器类似于责任链中的节点,可独立处理逻辑,也可中断链条。这种结构广泛存在于Spring的AOP、Bean生命周期、请求流程等模块,是Spring架构灵活性的基础之一。

SpringBoot代码案例

以下是一个基于 Spring Boot实现的责任链模式示例,处理用户注册后的后续处理。

java 复制代码
// 责任链接口
public interface RegisterHandler {
    void handle(User user, RegisterHandlerChain chain);
}

// 责任链调度器
@Component
public class RegisterHandlerChain {

    private final List<RegisterHandler> handlers;

    @Autowired
    public RegisterHandlerChain(List<RegisterHandler> handlers) {
        this.handlers = handlers;
    }

    public void execute(User user) {
        new InternalChain(handlers).proceed(user);
    }

    private static class InternalChain {
        private final Iterator<RegisterHandler> iterator;

        public InternalChain(List<RegisterHandler> handlers) {
            this.iterator = handlers.iterator();
        }

        public void proceed(User user) {
            if (iterator.hasNext()) {
                RegisterHandler handler = iterator.next();
                handler.handle(user, this);
            }
        }
    }
}

// 欢迎邮件处理器
@Component
public class WelcomeEmailHandler implements RegisterHandler {
    public void handle(User user, RegisterHandlerChain.InternalChain chain) {
        System.out.println("发送欢迎邮件给:" + user.getUsername());
        chain.proceed(user);
    }
}

// 积分处理器
@Component
public class AddBonusHandler implements RegisterHandler {
    public void handle(User user, RegisterHandlerChain.InternalChain chain) {
        System.out.println("给用户:" + user.getUsername() + " 加入100积分");
        chain.proceed(user);
    }
}

// 日志处理器
@Component
public class LogRegisterHandler implements RegisterHandler {
    public void handle(User user, RegisterHandlerChain.InternalChain chain) {
        System.out.println("记录日志:用户 " + user.getUsername() + " 完成注册");
        chain.proceed(user);
    }
}

// 注册服务
@Service
public class RegisterService {

    @Autowired
    private RegisterHandlerChain handlerChain;

    public void register(User user) {
        System.out.println("保存用户到数据库:" + user.getUsername());
        handlerChain.execute(user);
    }
}

// 简单的用户对象
public class User {
    private String username;
    // constructor, getter, setter
}

在这个案例中,每个校验器都只负责自己的校验逻辑,整体校验逻辑由责任链构建器按需组装,具备高度可插拔性和可维护性。后续如需增加手机号校验、验证码校验,仅需实现新的校验器并插入链中即可,符合开闭原则。

总结

责任链模式通过链式结构将请求处理逻辑解耦成多个节点,每个节点独立负责一个职责点,使流程更清晰、扩展更容易。在Spring中,HandlerInterceptor、Filter、BeanPostProcessor等都大量使用该模式构建可组合、可中断的处理链。掌握责任链模式,不仅能优化流程型代码,更是解构"系统职责"的关键思维方式。

(看到这 && 对您有帮助 && 觉得我总结的还行) -> 受累点个免费的赞👍,谢谢

责任链模式 对比 观察者模式

下面用过实现相同的业务来对比一下这两种设计模式,方便大家对比记忆。

场景设定

业务场景很简单也很常见:

用户注册后,系统需要:

  1. 发送欢迎邮件
  2. 给新用户加积分
  3. 写一条系统日志

第一版:责任链模式实现用户注册流程

思路

用户注册服务类依次执行一条条逻辑,每条逻辑是链条上的一个处理器,一个处理完再传给下一个

代码见上方SpringBoot代码案例

第二版:观察者模式实现用户注册流程

思路

用户注册服务发布一个事件,所有监听器独立响应,互不干扰。

java 复制代码
// 自定义注册事件
public class UserRegisterEvent extends ApplicationEvent {
    private final User user;

    public UserRegisterEvent(Object source, User user) {
        super(source);
        this.user = user;
    }

    public User getUser() {
        return user;
    }
}

// 欢迎邮件监听器
@Component
public class WelcomeEmailListener implements ApplicationListener<UserRegisterEvent> {
    public void onApplicationEvent(UserRegisterEvent event) {
        System.out.println("发送欢迎邮件给:" + event.getUser().getUsername());
    }
}

// 积分监听器
@Component
public class AddBonusListener implements ApplicationListener<UserRegisterEvent> {
    public void onApplicationEvent(UserRegisterEvent event) {
        System.out.println("给用户:" + event.getUser().getUsername() + " 加入100积分");
    }
}

// 日志监听器
@Component
public class LogRegisterListener implements ApplicationListener<UserRegisterEvent> {
    public void onApplicationEvent(UserRegisterEvent event) {
        System.out.println("记录日志:用户 " + event.getUser().getUsername() + " 完成注册");
    }
}

// 注册服务
@Service
public class RegisterService {

    @Autowired
    private ApplicationEventPublisher publisher;

    public void register(User user) {
        System.out.println("保存用户到数据库:" + user.getUsername());
        publisher.publishEvent(new UserRegisterEvent(this, user));
    }
}

两种模式都可以处理用户注册扩展动作

但如果:

  • 需要按顺序严格处理+中途可能中断 ➔ 选择责任链模式
  • 需要独立处理+任意扩展监听 ➔ 选择观察者模式

对比分析总结

维度 责任链模式实现 观察者模式实现
控制流 严格顺序 处理,且可以中断处理链 广播式通知,全部观察者独立处理
处理者之间 先后顺序依赖,比如邮件→积分→日志 完全无序,各自监听,互不依赖
中断机制 可以根据业务情况中止后续处理(如验证失败时停止链) 通常不能中断,所有监听器都会被通知
扩展性 新增处理器需要插入链条,控制顺序,稍显繁琐 新增监听器只需注册,无需修改原有逻辑,天然扩展
适合场景 严格流程控制、有明确上下游依赖的操作链(如审批流、过滤器链) 松耦合、异步通知、多方响应(如事件驱动)
Spring中的体现 FilterChain、Interceptor链 ApplicationEventPublisher、Listener机制

总结

  • 责任链模式 :适合有流程顺序、节点可中断的操作。比如:表单校验、权限审批。
  • 观察者模式 :适合一件事触发多个独立响应。比如:用户注册,系统通知、加积分、发消息。

(对您有帮助 && 觉得我总结的还行) -> 受累点个免费的赞👍,谢谢

相关推荐
RationalDysaniaer8 分钟前
Go设计模式-观察者模式
观察者模式·设计模式·golang
千千寰宇38 分钟前
[设计模式/Java] 设计模式之解释器模式【27】
数据库·设计模式
麓殇⊙1 小时前
设计模式-- 原型模式详解
设计模式·原型模式
电子科技圈1 小时前
XMOS空间音频——在任何设备上都能提供3D沉浸式空间音频且实现更安全地聆听
经验分享·设计模式·性能优化·计算机外设·音视频
智想天开1 小时前
11.原型模式:思考与解读
设计模式·原型模式
XiaoLeisj2 小时前
【设计模式】深入解析代理模式(委托模式):代理模式思想、静态模式和动态模式定义与区别、静态代理模式代码实现
java·spring boot·后端·spring·设计模式·代理模式·委托模式
pwzs2 小时前
常见的 Spring Boot 注解汇总
java·spring boot·后端·spring
非ban必选3 小时前
spring-ai使用Document存储至milvus的数据结构
前端·spring·milvus
无业哥4 小时前
Mac搭建Spring5源码环境
spring
星星点点洲6 小时前
【设计模式区别】装饰器模式和适配器模式区别
设计模式·适配器模式·装饰器模式