责任链的两种处理方式
1、请求会被 所有的处理器都处理一遍,不存在中途终止的情况,这里参照 MyBatis 拦截器理解
2、二则是处理器链执行请求中,某一处理器执行时,如果不符合自制定规则的话,停止流程,并且剩下未执行处理器就不会被执行,大家参照 SpringMvc 拦截器理解
需要注意的问题
业务场景一:对某个功能设计一套校验规则(必填校验、非法字符校验、长度校验)
这里就不具体完成必填校验、非法字符校验、长度校验的规则了,以以下的校验规则为准,思想是类似的
非空校验、敏感词校验处理器
将两个处理器串成链
通过容器上下文获取指定类型的bean,添加到待处理集合中,由VerifyHandlerChain的verify方法处理 待处理集合,调用每个处理器的verify方法
业务场景二:对创建订单功能设计一套基础校验规则
接口设计
创建一个责任链上下文容器,用于存储与责任链相应的子任务。
public final class OrderCreateChainContext<T> implements CommandLineRunner {
private final List<OrderCreateChainHandler> orderCreateChainHandlerContainer = new ArrayList();
/**
* 责任链组件执行
*
* @param requestParam 请求参数
*/
public void handler(T requestParam) {
// 此处根据 Ordered 实际值进行排序处理
orderCreateChainHandlerContainer.stream()
.sorted(Comparator.comparing(Ordered::getOrder)).forEach(each -> each.handler(requestParam));
}
@Override
public void run(String... args) throws Exception {
// 通过 Spring 上下文容器,获取所有 CreateOrderChainContext Bean
Map<String, OrderCreateChainHandler> chainFilterMap = ApplicationContextHolder.getBeansOfType(OrderCreateChainHandler.class);
// 将对应 Bean 放入责任链上下文容器中
chainFilterMap.forEach((beanName, bean) -> orderCreateChainHandlerContainer.add(bean););
}
}
接口实现类
其中请求参数封装为一个OrderCreateCommand
// 订单创建参数必填检验
@Component
public final class OrderCreateParamNotNullChainHandler implements OrderCreateChainHandler<OrderCreateCommand> {
@Override
public void handler(OrderCreateCommand requestParam) {
// 逻辑执行
}
@Override
public int getOrder() {
return 0;
}
}
// 订单创建参数正确性检验
@Component
public final class OrderCreateParamVerificationChainHandler implements OrderCreateChainHandler<OrderCreateCommand> {
@Override
public void handler(OrderCreateCommand requestParam) {
// 逻辑执行
}
@Override
public int getOrder() {
return 1;
}
}
// 订单创建商品 SKU 库存验证
@Component
public final class OrderCreateProductSkuStockChainHandler implements OrderCreateChainHandler<OrderCreateCommand> {
@Override
public void handler(OrderCreateCommand requestParam) {
// 逻辑执行
}
@Override
public int getOrder() {
return 2;
}
}
实际使用
@RequiredArgsConstructor
public class OrderServiceImpl implements OrderService {
private final OrderCreateChainContext<OrderCreateCommand> orderCreateChainContext;
public String createOrder(OrderCreateCommand requestParam) {
// 责任链模式: 执行订单创建参数验证
orderCreateChainContext.handler(requestParam);
}
}
责任链抽象(封装责任链模式组件)
当业务使用越来越多的情况下,重复定义 OrderCreateChainHandler 以及 OrderCreateChainContext 会增加系统冗余代码量。
可以考虑将这两个基础类抽象出来,作为基础组件库中的通用组件,供所有系统下的业务使用,从而避免代码冗余。
抽象基础类
抽象责任链处理接口
抽象责任链上下文
定义抽象责任链上下文,等同于 OrderCreateChainContext。可以看到保存责任链处理类的容器从 List 改为了 Map,这样可以方便扩展更多的不同业务责任链子类。
public final class AbstractChainContext<T> implements CommandLineRunner {
private final Map<String, List<AbstractChainHandler>> abstractChainHandlerContainer = Maps.newHashMap();
/**
* 责任链组件执行
*
* @param requestParam 请求参数
*/
public void handler(String mark, T requestParam) {
abstractChainHandlerContainer.get(mark).stream()
.sorted(Comparator.comparing(Ordered::getOrder)).forEach(each -> each.handler(requestParam));
}
@Override
public void run(String... args) throws Exception {
// 获取 Spring IOC 容器中所有 AbstractChainHandler 接口实现
Map<String, AbstractChainHandler> chainFilterMap = ApplicationContextHolder.getBeansOfType(AbstractChainHandler.class);
chainFilterMap.forEach((beanName, bean) -> {
List<AbstractChainHandler> abstractChainHandlers = abstractChainHandlerContainer.get(bean.mark());
if (abstractChainHandlers == null) {
abstractChainHandlers = new ArrayList();
}
abstractChainHandlers.add(bean);
// 根据 mark 标识将责任链模式分类,放入责任链容器上下文中
abstractChainHandlerContainer.put(bean.mark(), abstractChainHandlers);
});
}
}
run方法首先使用ioc容器获取所有接口实现类,然后流式编程,对每个类别的bean(接口实现类),判断是否已经将个类别组的list存入了待处理容器abstractChainHandlerContainer中,如果存入了(即list非空),则直接将这个bean添加到这个list中,如果未存入(即list为空),说明当前的bean是这个类别组的第一个,需要new一个list并将bean添加到list中,再将list存入待处理容器abstractChainHandlerContainer
抽象业务接口
继续探讨责任链子类的编写,只需要将之前的 OrderCreateChainHandler 实现接口改为 OrderCreateChainFilter 即可
// 订单创建参数必填检验
@Component
public final class OrderCreateParamNotNullChainHandler implements OrderCreateChainFilter<OrderCreateCommand> {
@Override
public void handler(OrderCreateCommand requestParam) {
// 逻辑执行
}
@Override
public int getOrder() {
return 0;
}
}
// 订单创建参数正确性检验
@Component
public final class OrderCreateParamVerificationChainHandler implements OrderCreateChainFilter<OrderCreateCommand> {
@Override
public void handler(OrderCreateCommand requestParam) {
// 逻辑执行
}
@Override
public int getOrder() {
return 1;
}
}
// 订单创建商品 SKU 库存验证
@Component
public final class OrderCreateProductSkuStockChainHandler implements OrderCreateChainFilter<OrderCreateCommand> {
@Override
public void handler(OrderCreateCommand requestParam) {
// 逻辑执行
}
@Override
public int getOrder() {
return 2;
}
}
使用
@RequiredArgsConstructor
public class OrderServiceImpl implements OrderService {
private final AbstractChainContext<OrderCreateCommand> abstractChainContext;
public String createOrder(OrderCreateCommand requestParam) {
// 责任链模式: 执行订单创建参数验证
abstractChainContext.handler(OrderChainMarkEnum.ORDER_CREATE_FILTER.name(), requestParam);
}
}
业务场景三:为用户注册设计一套校验规则
封装请求体
@Data
public class UserRegisterReqDTO {
/**
* 用户名
*/
private String username;
/**
* 密码
*/
private String password;
/**
* 真实姓名
*/
private String realName;
/**
* 证件类型
*/
private Integer idType;
/**
* 证件号
*/
private String idCard;
/**
* 手机号
*/
private String phone;
/**
* 邮箱
*/
private String mail;
/**
* 旅客类型
*/
private Integer userType;
/**
* 审核状态
*/
private Integer verifyState;
/**
* 邮编
*/
private String postCode;
/**
* 地址
*/
private String address;
/**
* 国家/地区
*/
private String region;
/**
* 固定电话
*/
private String telephone;
}
定义业务责任链接口
public interface UserRegisterCreateChainFilter<T extends UserRegisterReqDTO> extends AbstractChainHandler<UserRegisterReqDTO> {
@Override
default String mark() {
return UserChainMarkEnum.USER_REGISTER_FILTER.name();
}
}
当构建责任链时,为什么要定义具体业务责任链接口而不是直接实现抽象责任链类 AbstractChainHandler 呢?(责任链抽象部分 的 抽象业务接口 中的 抽象责任链过滤器也是这个原理)
其实就是使得不同业务的责任链接口是独立的,只展示出该业务相应的实现类,如果一味使用AbstractChainHandler,则可能展示出大量不同业务的实现类,另外,可能有些业务不需要提供mark,即不实现mark接口,因此对责任链接口做具体设计而不是抽象设计更胜一筹
定义责任链业务具体处理器
// 验证参数必填
@Component
public final class UserRegisterParamNotNullChainHandler implements UserRegisterCreateChainFilter<UserRegisterReqDTO> {
@Override
public void handler(UserRegisterReqDTO 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.getPhone())) {
throw new ClientException(UserRegisterErrorCodeEnum.PHONE_NOTNULL);
} else if (Objects.isNull(requestParam.getIdType())) {
throw new ClientException(UserRegisterErrorCodeEnum.ID_TYPE_NOTNULL);
} else if (Objects.isNull(requestParam.getIdCard())) {
throw new ClientException(UserRegisterErrorCodeEnum.ID_CARD_NOTNULL);
}
// xxx 这里应该把所有用户注册入参校验必填,因为重复工作量所以暂时验证上述这些
}
@Override
public int getOrder() {
return 0;
}
}
// 验证用户名是否可用
@Component
@RequiredArgsConstructor
public final class UserRegisterHasUsernameChainHandler implements UserRegisterCreateChainFilter<UserRegisterReqDTO> {
private final UserLoginService userLoginService;
@Override
public void handler(UserRegisterReqDTO requestParam) {
if (!userLoginService.hasUsername(requestParam.getUsername())) {
throw new ClientException(UserRegisterErrorCodeEnum.HAS_USERNAME_NOTNULL);
}
}
@Override
public int getOrder() {
return 1;
}
}
// 验证证件号是否多次注销,如果是的话加入黑名单
@Component
@RequiredArgsConstructor
public final class UserRegisterCheckDeletionChainHandler implements UserRegisterCreateChainFilter<UserRegisterReqDTO> {
private final UserService userService;
@Override
public void handler(UserRegisterReqDTO requestParam) {
Integer userDeletionNum = userService.queryUserDeletionNum(requestParam.getIdType(), requestParam.getIdCard());
if (userDeletionNum >= 5) {
throw new ClientException("证件号多次注销账号已被加入黑名单");
}
}
@Override
public int getOrder() {
return 2;
}
}
将以上各种handler分组存入待处理集合
public final class AbstractChainContext<T> implements CommandLineRunner {
private final Map<String, List<AbstractChainHandler>> abstractChainHandlerContainer = Maps.newHashMap();
/**
* 责任链组件执行
*
* @param requestParam 请求参数
*/
public void handler(String mark, T requestParam) {
abstractChainHandlerContainer.get(mark).stream()
.sorted(Comparator.comparing(Ordered::getOrder)).forEach(each -> each.handler(requestParam));
}
@Override
public void run(String... args) throws Exception {
// 获取 Spring IOC 容器中所有 AbstractChainHandler 接口实现
Map<String, AbstractChainHandler> chainFilterMap = ApplicationContextHolder.getBeansOfType(AbstractChainHandler.class);
chainFilterMap.forEach((beanName, bean) -> {
List<AbstractChainHandler> abstractChainHandlers = abstractChainHandlerContainer.get(bean.mark());
if (abstractChainHandlers == null) {
abstractChainHandlers = new ArrayList();
}
abstractChainHandlers.add(bean);
// 根据 mark 标识将责任链模式分类,放入责任链容器上下文中
abstractChainHandlerContainer.put(bean.mark(), abstractChainHandlers);
});
}
}
使用
@Slf4j
@Service
@RequiredArgsConstructor
public class UserLoginServiceImpl implements UserLoginService {
private final AbstractChainContext<UserRegisterReqDTO> abstractChainContext;
@Transactional(rollbackFor = Exception.class)
@Override
public UserRegisterRespDTO register(UserRegisterReqDTO requestParam) {
abstractChainContext.handler(UserChainMarkEnum.USER_REGISTER_FILTER.name(), requestParam);
...
}
}