SpringBoot使用设计模式一责任链模式
一、前言
在日常开发中,经常会遇到需要对某个请求进行多步处理的场景。例如用户注册流程,需要依次完成参数校验、手机号合法性验证、用户信息查重、密码加密、数据入库等操作;再比如接口请求的拦截处理,需要经过token验证、权限校验、限流控制、日志记录等步骤。
如果采用传统的写法,可能会出现如下的代码:
public R<?> register(UserRegisterDTO registerDTO) {
// 1. 参数校验
if (registerDTO.getUsername() == null || registerDTO.getPassword() == null) {
return R.fail("用户名或密码不能为空");
}
// 2. 手机号验证
if (!Pattern.matches("^1[3-9]\\d{9}$", registerDTO.getPhone())) {
return R.fail("手机号格式不正确");
}
// 3. 用户查重
if (userMapper.existsByUsername(registerDTO.getUsername())) {
return R.fail("用户名已存在");
}
// 4. 密码加密
registerDTO.setPassword(passwordEncoder.encode(registerDTO.getPassword()));
// 5. 数据入库
userMapper.insert(convertToEntity(registerDTO));
return R.success("注册成功");
}
这种写法存在明显的问题:代码臃肿且耦合度高,每新增一个校验步骤都需要修改原有方法,违反开闭原则;步骤之间的顺序固定,无法灵活调整;单个步骤的逻辑无法复用,若其他场景需要用到其中某个校验规则,只能重复编写。
针对这种多步骤、可组合、可扩展的处理场景,责任链模式是绝佳的解决方案。
二、责任链模式
责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,它将请求的处理者串联成一条链,请求沿着这条链依次传递,直到链中的某个处理者能够处理该请求为止。
核心角色
- 抽象处理者(Handler):定义处理请求的接口,包含一个指向下一处理者的引用,以及处理请求的抽象方法;
- 具体处理者(Concrete Handler):实现抽象处理者接口,封装具体的处理逻辑,判断自身是否能处理请求,若能处理则处理,否则将请求传递给下一个处理者;
- 客户端(Client):创建责任链,并将请求提交到链的首端,无需关心请求的具体处理过程。
使用场景
- 一个请求需要经过多个步骤处理,且步骤顺序可调整;
- 不确定请求的处理者或处理顺序,需要动态组合处理流程;
- 希望避免请求的发送者与接收者之间的紧耦合。
优点
- 降低耦合度:请求发送者与处理者解耦,发送者无需知道请求的处理者及处理流程;
- 增强灵活性:可动态调整责任链的顺序、新增或移除处理者,符合开闭原则;
- 便于复用:每个处理者职责单一,可在不同的责任链中复用。
缺点
- 请求可能无法被处理:若责任链中没有处理者能处理请求,可能导致请求丢失(需提前设计兜底方案);
- 调试难度增加:请求的处理过程分散在多个处理者中,排查问题时需要跟踪整个链条。
三、实现案例
以用户注册流程为例,使用责任链模式重构代码,实现参数校验、手机号验证、用户查重、密码加密、数据入库等步骤的解耦与灵活组合。
3.1 定义请求实体与响应工具类
首先定义用户注册的请求参数实体,包含用户名、密码、手机号等核心字段:
@Data
@ApiModel(value = "用户注册请求")
public class UserRegisterDTO implements Serializable {
@ApiModelProperty(value = "用户名")
private String username;
@ApiModelProperty(value = "密码")
private String password;
@ApiModelProperty(value = "手机号")
private String phone;
}
定义统一的响应工具类(复用常用的R对象):
public class R<T> implements Serializable {
private boolean success;
private String message;
private T data;
// 成功响应静态方法
public static <T> R<T> success(String message, T data) {
R<T> r = new R<>();
r.setSuccess(true);
r.setMessage(message);
r.setData(data);
return r;
}
public static <T> R<T> success(String message) {
return success(message, null);
}
// 失败响应静态方法
public static <T> R<T> fail(String message) {
R<T> r = new R<>();
r.setSuccess(false);
r.setMessage(message);
return r;
}
// getter/setter省略
}
3.2 定义抽象处理者(Handler)
创建抽象处理者接口,定义处理请求的方法和设置下一个处理者的方法:
/**
* 注册流程抽象处理者
*/
public interface RegisterHandler {
/**
* 处理注册请求
* @param registerDTO 注册请求参数
* @return 处理结果
*/
R<?> handle(UserRegisterDTO registerDTO);
/**
* 设置下一个处理者
* @param nextHandler 下一个处理者
* @return 下一个处理者(支持链式调用)
*/
RegisterHandler setNext(RegisterHandler nextHandler);
}
为了简化具体处理者的实现,创建抽象基类,实现setNext方法和请求传递逻辑:
/**
* 注册流程处理者基类(实现默认的链式调用逻辑)
*/
public abstract class AbstractRegisterHandler implements RegisterHandler {
// 下一个处理者
protected RegisterHandler nextHandler;
@Override
public RegisterHandler setNext(RegisterHandler nextHandler) {
this.nextHandler = nextHandler;
// 返回下一个处理者,支持链式构建责任链
return nextHandler;
}
/**
* 处理请求的模板方法:当前处理者处理完成后,传递给下一个处理者
*/
@Override
public R<?> handle(UserRegisterDTO registerDTO) {
// 子类实现具体处理逻辑
R<?> result = doHandle(registerDTO);
// 若当前处理成功且存在下一个处理者,则继续传递请求
if (result.isSuccess() && nextHandler != null) {
return nextHandler.handle(registerDTO);
}
// 处理失败或无下一个处理者,直接返回结果
return result;
}
/**
* 具体处理逻辑(由子类实现)
*/
protected abstract R<?> doHandle(UserRegisterDTO registerDTO);
}
3.3 实现具体处理者(Concrete Handler)
针对注册流程的每个步骤,创建对应的具体处理者类,继承抽象基类并实现doHandle方法:
3.3.1 参数校验处理者
@Component
@Slf4j
public class ParamValidateHandler extends AbstractRegisterHandler {
@Override
protected R<?> doHandle(UserRegisterDTO registerDTO) {
log.info("执行参数校验处理");
// 校验用户名、密码、手机号非空
if (StringUtils.isEmpty(registerDTO.getUsername())) {
return R.fail("用户名不能为空");
}
if (StringUtils.isEmpty(registerDTO.getPassword())) {
return R.fail("密码不能为空");
}
if (StringUtils.isEmpty(registerDTO.getPhone())) {
return R.fail("手机号不能为空");
}
// 校验密码长度(6-20位)
if (registerDTO.getPassword().length() < 6 || registerDTO.getPassword().length() > 20) {
return R.fail("密码长度必须在6-20位之间");
}
return R.success("参数校验通过");
}
}
3.3.2 手机号格式验证处理者
@Component
@Slf4j
public class PhoneValidateHandler extends AbstractRegisterHandler {
// 手机号正则表达式
private static final Pattern PHONE_PATTERN = Pattern.compile("^1[3-9]\\d{9}$");
@Override
protected R<?> doHandle(UserRegisterDTO registerDTO) {
log.info("执行手机号格式验证");
if (!PHONE_PATTERN.matcher(registerDTO.getPhone()).matches()) {
return R.fail("手机号格式不正确");
}
return R.success("手机号格式验证通过");
}
}
3.3.3 用户查重处理者
@Component
@Slf4j
public class UserDuplicateCheckHandler extends AbstractRegisterHandler {
@Autowired
private UserMapper userMapper;
@Override
protected R<?> doHandle(UserRegisterDTO registerDTO) {
log.info("执行用户查重处理");
// 检查用户名是否已存在
if (userMapper.existsByUsername(registerDTO.getUsername())) {
return R.fail("用户名已存在");
}
// 检查手机号是否已绑定
if (userMapper.existsByPhone(registerDTO.getPhone())) {
return R.fail("手机号已被注册");
}
return R.success("用户查重通过");
}
}
3.3.4 密码加密处理者
@Component
@Slf4j
public class PasswordEncodeHandler extends AbstractRegisterHandler {
@Autowired
private PasswordEncoder passwordEncoder;
@Override
protected R<?> doHandle(UserRegisterDTO registerDTO) {
log.info("执行密码加密处理");
// 对密码进行BCrypt加密
String encodedPassword = passwordEncoder.encode(registerDTO.getPassword());
// 更新加密后的密码到请求对象
registerDTO.setPassword(encodedPassword);
return R.success("密码加密成功");
}
}
3.3.5 数据入库处理者
@Component
@Slf4j
public class UserSaveHandler extends AbstractRegisterHandler {
@Autowired
private UserMapper userMapper;
@Override
protected R<?> doHandle(UserRegisterDTO registerDTO) {
log.info("执行用户数据入库处理");
// 转换DTO为实体类
User user = new User();
user.setUsername(registerDTO.getUsername());
user.setPassword(registerDTO.getPassword());
user.setPhone(registerDTO.getPhone());
user.setCreateTime(LocalDateTime.now());
// 入库操作
userMapper.insert(user);
return R.success("用户注册成功", user.getId());
}
}
3.4 构建责任链(工厂模式)
创建责任链工厂类,负责组装具体处理者,形成完整的处理链,避免客户端直接依赖多个处理者:
@Component
public class RegisterChainFactory {
// 注入所有具体处理者(Spring自动扫描AbstractRegisterHandler的实现类)
@Autowired
private List<AbstractRegisterHandler> handlerList;
/**
* 构建责任链(固定顺序:参数校验→手机号验证→用户查重→密码加密→数据入库)
* @return 责任链的首端处理者
*/
public RegisterHandler buildChain() {
// 校验处理者列表非空
if (CollectionUtils.isEmpty(handlerList)) {
throw new IllegalStateException("注册流程处理者不能为空");
}
// 按指定顺序排序(通过类名匹配顺序)
List<AbstractRegisterHandler> sortedHandlers = sortHandlers();
// 组装责任链:依次设置每个处理者的下一个节点
for (int i = 0; i < sortedHandlers.size() - 1; i++) {
sortedHandlers.get(i).setNext(sortedHandlers.get(i + 1));
}
// 返回链的首端(第一个处理者)
return sortedHandlers.get(0);
}
/**
* 按业务顺序排序处理者
*/
private List<AbstractRegisterHandler> sortHandlers() {
// 定义处理者的顺序:参数校验→手机号验证→用户查重→密码加密→数据入库
Map<Class<?>, Integer> orderMap = new HashMap<>();
orderMap.put(ParamValidateHandler.class, 1);
orderMap.put(PhoneValidateHandler.class, 2);
orderMap.put(UserDuplicateCheckHandler.class, 3);
orderMap.put(PasswordEncodeHandler.class, 4);
orderMap.put(UserSaveHandler.class, 5);
// 按orderMap定义的顺序排序
return handlerList.stream()
.sorted(Comparator.comparingInt(handler ->
orderMap.getOrDefault(handler.getClass(), Integer.MAX_VALUE)))
.collect(Collectors.toList());
}
}
3.5 控制器层调用(客户端)
控制器通过工厂获取责任链,发起注册请求,无需关心具体的处理步骤:
@RestController
@RequestMapping("/user")
@Slf4j
public class UserRegisterController {
@Autowired
private RegisterChainFactory registerChainFactory;
/**
* 用户注册接口
*/
@PostMapping("/register")
public R<?> register(@RequestBody @Valid UserRegisterDTO registerDTO) {
log.info("接收用户注册请求:{}", registerDTO);
// 从工厂获取责任链
RegisterHandler registerChain = registerChainFactory.buildChain();
// 发起请求(从链首开始传递)
return registerChain.handle(registerDTO);
}
}
四、责任链模式的进阶用法
4.1 动态调整责任链
实际开发中,可能需要根据不同场景动态调整责任链的步骤(例如某些场景不需要手机号验证)。可以通过工厂类的扩展方法实现:
/**
* 动态构建责任链(支持指定需要的处理者)
* @param includeHandlerClasses 需要包含的处理者类
* @return 自定义责任链
*/
public RegisterHandler buildDynamicChain(Set<Class<? extends AbstractRegisterHandler>> includeHandlerClasses) {
if (CollectionUtils.isEmpty(handlerList) || CollectionUtils.isEmpty(includeHandlerClasses)) {
throw new IllegalArgumentException("处理者列表或需要包含的处理者不能为空");
}
// 筛选需要的处理者并排序
List<AbstractRegisterHandler> selectedHandlers = handlerList.stream()
.filter(handler -> includeHandlerClasses.contains(handler.getClass()))
.sorted(Comparator.comparingInt(handler ->
orderMap.getOrDefault(handler.getClass(), Integer.MAX_VALUE)))
.collect(Collectors.toList());
// 组装责任链
for (int i = 0; i < selectedHandlers.size() - 1; i++) {
selectedHandlers.get(i).setNext(selectedHandlers.get(i + 1));
}
return selectedHandlers.get(0);
}
控制器中动态指定处理步骤:
/**
* 无需手机号验证的注册接口(例如后台管理系统创建用户)
*/
@PostMapping("/register/no-phone-validate")
public R<?> registerWithoutPhoneValidate(@RequestBody @Valid UserRegisterDTO registerDTO) {
log.info("接收无需手机号验证的注册请求:{}", registerDTO);
// 指定需要包含的处理者(排除PhoneValidateHandler)
Set<Class<? extends AbstractRegisterHandler>> includeHandlers = new HashSet<>();
includeHandlers.add(ParamValidateHandler.class);
includeHandlers.add(UserDuplicateCheckHandler.class);
includeHandlers.add(PasswordEncodeHandler.class);
includeHandlers.add(UserSaveHandler.class);
// 构建动态责任链
RegisterHandler registerChain = registerChainFactory.buildDynamicChain(includeHandlers);
return registerChain.handle(registerDTO);
}
4.2 注解式配置责任链顺序
为了避免在工厂类中硬编码处理者顺序,可通过自定义注解标记处理者的优先级:
/**
* 责任链顺序注解
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface HandlerOrder {
// 顺序值越小,优先级越高
int value();
}
在具体处理者上添加注解:
@Component
@Slf4j
@HandlerOrder(1) // 优先级1:最先执行
public class ParamValidateHandler extends AbstractRegisterHandler {
// ... 原有逻辑
}
@Component
@Slf4j
@HandlerOrder(2) // 优先级2:次之
public class PhoneValidateHandler extends AbstractRegisterHandler {
// ... 原有逻辑
}
改造工厂类的排序逻辑:
/**
* 基于注解排序处理者
*/
private List<AbstractRegisterHandler> sortHandlersByAnnotation() {
return handlerList.stream()
.sorted(Comparator.comparingInt(handler -> {
HandlerOrder annotation = handler.getClass().getAnnotation(HandlerOrder.class);
return annotation != null ? annotation.value() : Integer.MAX_VALUE;
}))
.collect(Collectors.toList());
}
4.3 结合配置文件实现可配置责任链
将责任链的处理者顺序配置在application.yml中,实现无需修改代码即可调整流程:
# 注册责任链配置:key为处理者类名(简化版),value为顺序
register:
chain:
order:
ParamValidateHandler: 1
PhoneValidateHandler: 2
UserDuplicateCheckHandler: 3
PasswordEncodeHandler: 4
UserSaveHandler: 5
定义配置实体类:
@Data
@Component
@ConfigurationProperties(prefix = "register.chain")
public class RegisterChainProperties {
// 处理者顺序配置:key=处理者类名(简单类名),value=顺序
private Map<String, Integer> order;
}
改造工厂类的排序逻辑:
@Component
public class RegisterChainFactory {
@Autowired
private List<AbstractRegisterHandler> handlerList;
@Autowired
private RegisterChainProperties chainProperties;
/**
* 基于配置文件排序处理者
*/
private List<AbstractRegisterHandler> sortHandlersByConfig() {
Map<String, Integer> orderConfig = chainProperties.getOrder();
if (CollectionUtils.isEmpty(orderConfig)) {
throw new IllegalStateException("责任链顺序配置不能为空");
}
return handlerList.stream()
.sorted(Comparator.comparingInt(handler -> {
// 获取处理者的简单类名
String className = handler.getClass().getSimpleName();
return orderConfig.getOrDefault(className, Integer.MAX_VALUE);
}))
.collect(Collectors.toList());
}
}
4.4 责任链的中断与兜底处理
为了避免请求丢失,可在责任链末尾添加兜底处理者,确保所有请求都有响应;同时支持手动中断责任链(例如某些特殊场景需要终止流程):
4.4.1 兜底处理者
@Component
@Slf4j
@HandlerOrder(6) // 最后执行
public class FallbackHandler extends AbstractRegisterHandler {
@Override
protected R<?> doHandle(UserRegisterDTO registerDTO) {
log.warn("注册流程未正常完成,执行兜底处理");
return R.fail("注册失败,请联系客服");
}
}
4.4.2 支持手动中断责任链
在抽象基类中添加中断方法,允许具体处理者主动终止流程:
public abstract class AbstractRegisterHandler implements RegisterHandler {
protected RegisterHandler nextHandler;
// 标记是否中断责任链
private boolean interrupted = false;
/**
* 中断责任链
*/
protected void interrupt() {
this.interrupted = true;
}
@Override
public R<?> handle(UserRegisterDTO registerDTO) {
R<?> result = doHandle(registerDTO);
// 若已中断或无下一个处理者,直接返回
if (interrupted || nextHandler == null) {
return result;
}
// 继续传递请求
return nextHandler.handle(registerDTO);
}
// ... 其他原有方法
}
在具体处理者中使用:
@Component
@Slf4j
public class SpecialUserHandler extends AbstractRegisterHandler {
@Autowired
private SpecialUserService specialUserService;
@Override
protected R<?> doHandle(UserRegisterDTO registerDTO) {
log.info("检测特殊用户");
if (specialUserService.isSpecialUser(registerDTO.getUsername())) {
// 特殊用户直接注册成功,中断责任链
interrupt();
return R.success("特殊用户快速注册成功");
}
return R.success("非特殊用户,继续流程");
}
}
五、总结
本文通过用户注册场景,详细介绍了责任链模式在SpringBoot中的落地实现,主要收获如下:
- 解耦处理步骤:将多步处理逻辑拆分为独立的处理者类,每个类职责单一,便于维护和复用;
- 增强灵活性:支持动态调整责任链的顺序、新增/移除处理者,无需修改核心业务代码,符合开闭原则;
- 简化客户端调用:客户端只需发起请求,无需关心处理流程和处理者,降低了代码耦合;
- 支持多种进阶用法:通过注解、配置文件、动态组装等方式,满足不同场景的需求。
责任链模式的适用场景非常广泛,除了注册流程,还可用于接口请求拦截、数据校验、工作流审批、日志收集等场景。在实际开发中,结合工厂模式、注解、配置文件等技术,可以进一步提升责任链的灵活性和可维护性,是优化多步骤业务流程的优选方案。

浙公网安备 33010602011771号