抽象责任链体系由 5 个关键组件构成
责任链上下文
它是责任链的 "大脑",负责处理器的注册、管理和执行调度,是整个模式的核心调度中心。
abstractChainHandlerContainer
:一个Map<String, List<AbstractChainHandler>>
,key 是 "责任链标识(mark)",value 是该标识下的所有处理器列表。作用是按 "业务分组" 管理处理器(比如 "用户注册" 一个组,"订单提交" 一个组)。
handler(String mark, T requestParam)
:对外提供的执行入口。根据传入的mark
从容器中取出对应处理器列表,逐个执行处理器的handler
方法(即按顺序执行链式逻辑)。若列表为空,直接抛异常(避免无处理器时的业务漏洞)。
run(String... args)
:实现CommandLineRunner
接口(Spring 容器启动后自动执行),负责初始化处理器。从 Spring 容器中获取所有AbstractChainHandler
类型的 Bean,按mark
分组存入容器;同时对每个组内的处理器按getOrder()
返回值排序(保证执行顺序可控)。
java
/**
* 抽象责任链上下文
*/
public final class AbstractChainContext<T> implements CommandLineRunner {
private final Map<String, List<AbstractChainHandler>> abstractChainHandlerContainer = new HashMap<>();
/**
* 责任链组件执行
*
* @param mark 责任链组件标识
* @param requestParam 请求参数
*/
public void handler(String mark, T requestParam) {
List<AbstractChainHandler> abstractChainHandlers = abstractChainHandlerContainer.get(mark);
if (CollectionUtils.isEmpty(abstractChainHandlers)) {
throw new RuntimeException(String.format("[%s] Chain of Responsibility ID is undefined.", mark));
}
abstractChainHandlers.forEach(each -> each.handler(requestParam));
}
@Override
public void run(String... args) throws Exception {
Map<String, AbstractChainHandler> chainFilterMap = ApplicationContextHolder
.getBeansOfType(AbstractChainHandler.class);
chainFilterMap.forEach((beanName, bean) -> {
List<AbstractChainHandler> abstractChainHandlers = abstractChainHandlerContainer.get(bean.mark());
if (CollectionUtils.isEmpty(abstractChainHandlers)) {
abstractChainHandlers = new ArrayList();
}
abstractChainHandlers.add(bean);
List<AbstractChainHandler> actualAbstractChainHandlers = abstractChainHandlers.stream()
.sorted(Comparator.comparing(Ordered::getOrder))
.collect(Collectors.toList());
abstractChainHandlerContainer.put(bean.mark(), actualAbstractChainHandlers);
});
}
}
处理器抽象接口
它是所有具体处理器的 "规范契约",定义了处理器的核心能力。
继承Ordered
接口(Spring 的排序接口),因此所有处理器必须实现getOrder()
方法 ------ 用于定义自身在链中的执行顺序(数字越小,优先级越高)。
handler(T requestParam)
:处理器的核心业务方法,实现具体的链式处理逻辑(如参数校验、数据转换等)。
mark()
:返回 "责任链标识",用于将处理器归到对应的业务组(比如用户注册相关的处理器,mark
统一为 "USER_REGISTER_FILTER")。
java
/**
* 抽象业务责任链组件
*/
public interface AbstractChainHandler<T> extends Ordered {
/**
* 执行责任链逻辑
*
* @param requestParam 责任链执行入参
*/
void handler(T requestParam);
/**
* @return 责任链组件标识
*/
String mark();
}
业务专属处理器接口
它是特定业务场景的处理器接口 (这里是 "用户注册" 场景),继承AbstractChainHandler
并固化了mark
,避免具体处理器重复定义标识。
核心实现 :默认重写mark()
方法,返回UserChainMarkEnum.USER_REGISTER_FILTER.name()
------ 即所有实现该接口的处理器,都会被自动归到 "用户注册" 这个责任链组(无需每个处理器单独写mark
,减少重复代码)。
java
public interface UserRegisterCreateFilter<T extends AuthUserDTO> extends AbstractChainHandler<AuthUserDTO> {
@Override
default String mark() {
return UserChainMarkEnum.USER_REGISTER_FILTER.name();
}
}
具体处理器
它们是责任链的 "执行者",负责实现具体的业务逻辑(如参数校验、规则判断等)。以示例中的两个处理器为例:
-
UserRegisterParamNotNullChainHandler
:- 重写
handler
:校验AuthUserDTO
中的必填参数(用户名、密码、邮箱、手机号),若有 null 则抛异常(中断链式执行)。 - 重写
getOrder()
:返回 0(优先级最高,需最先执行 ------ 参数校验必须在业务校验前)。
- 重写
-
UserRegisterHasUsernameChainHandler
:- 重写
handler
:调用authUserService
检查用户名是否已存在,若存在则抛异常。 - 重写
getOrder()
:返回 1(优先级次之,参数校验通过后再检查用户名唯一性)。
- 重写
java
@Component
public class UserRegisterHasUsernameChainHandler implements UserRegisterCreateFilter<AuthUserDTO>{
@Resource
private AuthUserService authUserService;
@Override
public void handler(AuthUserDTO requestParam) {
if (authUserService.hasUsername(requestParam)){
throw new ClientException(UserRegisterErrorCodeEnum.HAS_USERNAME_NOTNULL);
}
}
@Override
public int getOrder() {
return 1;
}
}
@Component
public final class UserRegisterParamNotNullChainHandler implements UserRegisterCreateFilter<AuthUserDTO>{
@Override
public void handler(AuthUserDTO requestParam) {
if (Objects.isNull(requestParam.getUserName())) {
throw new ClientException(UserRegisterErrorCodeEnum.USER_NAME_NOTNULL);
}else if (Objects.isNull(requestParam.getPassword())) {
throw new ClientException(UserRegisterErrorCodeEnum.PASSWORD_NOTNULL);
}else if (Objects.isNull(requestParam.getEmail())) {
throw new ClientException(UserRegisterErrorCodeEnum.MAIL_NOTNULL);
}else if (Objects.isNull(requestParam.getPhone())) {
throw new ClientException(UserRegisterErrorCodeEnum.PHONE_NOTNULL);
}
}
@Override
public int getOrder() {
return 0;
}
}
自动配置类
它是责任链与 Spring 容器的连接点 ,负责将AbstractChainContext
注册为 Spring Bean,使其能被全局注入使用。
通过@Bean
注解创建AbstractChainContext
实例,确保上下文由 Spring 管理,从而在启动时自动执行run
方法完成处理器初始化。
java
/**
* 设计模式自动装配
*/
@ImportAutoConfiguration(ApplicationBaseAutoConfiguration.class)
@Configuration
public class DesignPatternAutoConfiguration {
/**
* 责任链上下文
*/
@Bean
public AbstractChainContext abstractChainContext() {
return new AbstractChainContext();
}
}
执行流程
阶段 1:Spring 启动时的处理器初始化(AbstractChainContext.run()
)
-
扫描处理器 :Spring 容器启动完成后,
AbstractChainContext
作为CommandLineRunner
,自动执行run
方法。通过ApplicationContextHolder.getBeansOfType(AbstractChainHandler.class)
,从容器中获取所有标注了@Component
的处理器(如UserRegisterParamNotNullChainHandler
、UserRegisterHasUsernameChainHandler
)。 -
按 mark 分组 :遍历所有处理器,根据
mark()
返回值(这里两个处理器都通过UserRegisterCreateFilter
默认返回 "USER_REGISTER_FILTER"),将它们归到同一组(key 为 "USER_REGISTER_FILTER",value 为包含两个处理器的列表)。 -
按 order 排序 :对每个组内的处理器列表排序 ------ 按
getOrder()
返回值升序排列(0 在前,1 在后),最终该组列表顺序为:UserRegisterParamNotNullChainHandler
(order 0)→UserRegisterHasUsernameChainHandler
(order 1)。 -
存入容器 :将排序后的列表存入
abstractChainHandlerContainer
,完成初始化。
阶段 2:业务调用时的链式执行(AbstractChainContext.handler()
)
当用户注册接口被调用,需要执行校验逻辑时:
-
调用入口 :业务代码中注入
AbstractChainContext
,调用handler("USER_REGISTER_FILTER", authUserDTO)
(传入用户注册的mark
和请求参数)。 -
获取处理器列表 :上下文从
abstractChainHandlerContainer
中取出 key 为 "USER_REGISTER_FILTER" 的列表(即排序后的两个处理器)。 -
顺序执行处理器:
- 先执行
UserRegisterParamNotNullChainHandler.handler(authUserDTO)
:检查参数是否为空。若参数缺失(如 userName 为 null),直接抛ClientException
(链式执行中断,后续处理器不执行)。 - 若参数校验通过,再执行
UserRegisterHasUsernameChainHandler.handler(authUserDTO)
:检查用户名是否已存在。若已存在,抛异常中断;若通过,整个链式执行完成。
- 先执行
总结
套抽象责任链模式,本质是通过上下文做调度 、接口做规范 、Spring 做整合 ,将 "多步骤业务处理" 拆分为独立的处理器,实现了 "逻辑解耦 + 顺序可控 + 灵活扩展"。尤其适合校验流程、多环节业务处理 (如注册、下单、审批)等场景 ------ 新增步骤只需加处理器,调整顺序只需改getOrder
,极大降低了业务迭代的成本。