责任链概念
业务大多是串联的
责任链模式(Chain of Responsibility Pattern)是一种行为设计模式,它允许一个请求沿着一条由多个处理者组成的链传递,这种模式使得请求的发送者和接收者之间解耦,从而提高系统的灵活性和可扩展性。
本文将责任链分为单例链和多例链两种类型。
单例链是指每个节点的处理逻辑和指针是不可分割的 这使得两个逻辑链如果有相同的逻辑则需要创建两个实例
多例链是指每个节点的处理逻辑和指针是分开的 通过定义ILogicHandler
接口来实现解耦
单例链

其中ILogicChainArmory
接口定义了责任链的链式结构,ILogicLink
接口继承自ILogicChainArmory
,并定义了处理请求的方法。AbstractLogicLink
类实现了ILogicLink
接口,并提供了下一个节点的处理逻辑。
// 责任链接口
public interface ILogicChainArmory<T, D, R> {
// 获取下一个节点
ILogicLink<T, D, R> next();
// 设置下一个节点
ILogicLink<T, D, R> appendNext(ILogicLink<T, D, R> next);
}
public interface ILogicLink<T, D, R> extends ILogicChainArmory<T, D, R> {
// 处理请求
R apply(T requestParameter, D dynamicContext) throws Exception;
}
public abstract class AbstractLogicLink<T, D, R> implements ILogicLink<T, D, R> {
// 下一个节点
private ILogicLink<T, D, R> next;
@Override
public ILogicLink<T, D, R> next() {
return next;
}
@Override
public ILogicLink<T, D, R> appendNext(ILogicLink<T, D, R> next) {
this.next = next;
return next;
}
protected R next(T requestParameter, D dynamicContext) throws Exception {
return next.apply(requestParameter, dynamicContext);
}
}
在使用时,创建一个链的实例,并将各个处理器链接起来:
public void test_model01_01() throws Exception {
ruleLogic101.appendNext(ruleLogic102);
String logic = logicLink.apply("123", new Rule02TradeRuleFactory.DynamicContext());
log.info("测试结果:{}", JSON.toJSONString(logic));
}
多例链
多例链是指每个节点的处理逻辑和指针是分开的。通过定义ILogicHandler
接口来实现解耦。

ILink
实际上是经典的链表结构,定义了基本的链表操作方法,LinkedList
实现了ILink
接口,提供了具体的链表操作。
BusinessLogic
类继承了LinkedList
,模版类使用了ILogicHandler
,代表每个节点是一个处理器
同时BusinessLinkedList
类实现了ILogicHandler
接口,代表整个链表也是一个处理器,其处理逻辑是遍历执行链表中的每个处理器
public interface ILink<E> {
boolean add(E e);
boolean addFirst(E e);
boolean addLast(E e);
boolean remove(Object o);
E get(int index);
void printLinkList();
}
// LinkedList实现比较多 这里省略
// 其内部定义了Node类 用于建立各个节点的关系
protected static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
public Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
// 处理器接口
public interface ILogicHandler<T, D, R> {
default R next(T requestParameter, D dynamicContext) {
return null;
}
R apply(T requestParameter, D dynamicContext) throws Exception;
}
// 本身也是一个处理器
public class BusinessLinkedList<T, D, R> extends LinkedList<ILogicHandler<T, D, R>> implements ILogicHandler<T, D, R>{
public BusinessLinkedList(String name) {
super(name);
}
// 执行所有节点的逻辑
@Override
public R apply(T requestParameter, D dynamicContext) throws Exception {
Node<ILogicHandler<T, D, R>> current = this.first;
do {
ILogicHandler<T, D, R> item = current.item;
R apply = item.apply(requestParameter, dynamicContext);
if (null != apply) return apply;
current = current.next;
} while (null != current);
return null;
}
}
// 用于快速创建责任链
public class LinkArmory<T, D, R> {
private final BusinessLinkedList<T, D, R> logicLink;
@SafeVarargs
public LinkArmory(String linkName, ILogicHandler<T, D, R>... logicHandlers) {
logicLink = new BusinessLinkedList<>(linkName);
for (ILogicHandler<T, D, R> logicHandler: logicHandlers){
logicLink.add(logicHandler);
}
}
public BusinessLinkedList<T, D, R> getLogicLink() {
return logicLink;
}
}
责任链的应用
锁单条件过滤
在锁单时,需要判断活动有效性和校验用户参与的条件,比如活动状态、是否过期、用户参与次数是否达到上限等等
如果直接面向过程进行检查,后期改动和维护会比较麻烦,因此选择使用责任链来完成这个需求,后期可以低成本改动
定义ActivityUsabilityRuleFilter
和UserTakeLimitRuleFilter
分别用于完成活动可用性过滤和用户限制过滤的需求
// 活动可用性
@Slf4j
@Service
public class ActivityUsabilityRuleFilter implements ILogicHandler<TradeRuleCommandEntity, TradeRuleFilterFactory.DynamicContext, TradeRuleFilterBackEntity> {
@Resource
private ITradeRepository repository;
@Override
public TradeRuleFilterBackEntity apply(TradeRuleCommandEntity requestParameter, TradeRuleFilterFactory.DynamicContext dynamicContext) throws Exception {
log.info("交易规则过滤-活动的可用性校验{} activityId:{}", requestParameter.getUserId(), requestParameter.getActivityId());
// 查询拼团活动
GroupBuyActivityEntity groupBuyActivity = repository.queryGroupBuyActivityEntityByActivityId(requestParameter.getActivityId());
// 校验;活动状态 - 可以抛业务异常code,或者把code写入到动态上下文dynamicContext中,最后获取。
if (!ActivityStatusEnumVO.EFFECTIVE.equals(groupBuyActivity.getStatus())) {
log.info("活动的可用性校验,非生效状态 activityId:{}", requestParameter.getActivityId());
throw new AppException(ResponseCode.E0101);
}
// 校验;活动时间
Date currentTime = new Date();
if (currentTime.before(groupBuyActivity.getStartTime()) || currentTime.after(groupBuyActivity.getEndTime())) {
log.info("活动的可用性校验,非可参与时间范围 activityId:{}", requestParameter.getActivityId());
throw new AppException(ResponseCode.E0102);
}
// 写入动态上下文
dynamicContext.setGroupBuyActivity(groupBuyActivity);
// 走到下一个责任链节点
return next(requestParameter, dynamicContext);
}
}
// 用户参与
@Slf4j
@Service
public class UserTakeLimitRuleFilter implements ILogicHandler<TradeRuleCommandEntity, TradeRuleFilterFactory.DynamicContext, TradeRuleFilterBackEntity> {
@Resource
private ITradeRepository repository;
@Override
public TradeRuleFilterBackEntity apply(TradeRuleCommandEntity requestParameter, TradeRuleFilterFactory.DynamicContext dynamicContext) throws Exception {
log.info("交易规则过滤-用户参与次数校验{} activityId:{}", requestParameter.getUserId(), requestParameter.getActivityId());
GroupBuyActivityEntity groupBuyActivity = dynamicContext.getGroupBuyActivity();
// 查询用户在一个拼团活动上参与的次数
Integer count = repository.queryOrderCountByActivityId(requestParameter.getActivityId(), requestParameter.getUserId());
if (null != groupBuyActivity.getTakeLimitCount() && count >= groupBuyActivity.getTakeLimitCount()) {
log.info("用户参与次数校验,已达可参与上限 activityId:{}", requestParameter.getActivityId());
throw new AppException(ResponseCode.E0103);
}
return TradeRuleFilterBackEntity.builder()
.userTakeOrderCount(count)
.build();
}
}
@Slf4j
@Service
public class TradeRuleFilterFactory {
// 返回最终形成的filter
@Bean("tradeRuleFilter")
public BusinessLinkedList<TradeRuleCommandEntity, TradeRuleFilterFactory.DynamicContext, TradeRuleFilterBackEntity> tradeRuleFilter(ActivityUsabilityRuleFilter activityUsabilityRuleFilter, UserTakeLimitRuleFilter userTakeLimitRuleFilter) {
// 组装链
LinkArmory<TradeRuleCommandEntity, TradeRuleFilterFactory.DynamicContext, TradeRuleFilterBackEntity> linkArmory =
new LinkArmory<>("交易规则过滤链", activityUsabilityRuleFilter, userTakeLimitRuleFilter);
// 链对象
// 使用时,会先执行ActivityUsabilityRuleFilter逻辑再执行UserTakeLimitRuleFilter逻辑
return linkArmory.getLogicLink();
}
// 动态上下文
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public static class DynamicContext {
private GroupBuyActivityEntity groupBuyActivity;
}
}
交易条件过滤
结算时也会有很多检查,比如交易Id是否有记录、拼团有效期校验、SC值动态过滤等等