在实际的项目生产活动中,我们经常会有很多前置处理,以及后置处理的需求。例如就拿简单的支付过程来说。
之前我们可能需要经过如下的环节:
- 根据支付请求,查询订单实际信息
- 根据实际订单信息,我们需要报送风控信息
- 查询优惠信息,进行优惠鉴权操作
…以上就是可能出现的流程环节。那实际生产过程中,我们应该考虑用什么样的方式更合理的完成呢?
如果大家有阅读源码的习惯,其实可以在各种各样的开源框架中发现这种需求的存在。
比如 Spring的filter,Sentinel的限流操作,还有netty的pipline
这就是我们今天要说的责任链模式
责任链模式
定义:创建多个对象,使这些对象形成一条链,并沿着这条链传递请求,直到链上的某一个对象决定处理此请求。
特点:
- 接受请求的对象连接成一条链,对象之间存在层级关系
- 这些对象可以处理这些请求,也可以传递请求
实战练习
接下来就来实现一下开头说的支付前流程,通过看Sentinel 源码,实现的责任链模式。
基本类图
ProcessorSolt
顶层节点类,该类定义了当前节点的行为,process 处理业务逻辑 ,fireProcess 触发下一个节点
public interface ProcessorSolt<T> {
/**
* 前置处理方法
*/
void process(T param);
/**
* 触发下一个
* @param param
*/
void fireProcess(T param);
}
AbstractLinkedProcessorSlot
抽象类,链条节点类,顾名思义,该类维护了一个节点的下级关系
其中复写了process方法,运用模版模式,让链条上的点专注于节点的业务逻辑,而不用关注怎么触发下一个节点的。(PS:Sentinel源码中,是每个Slot手动触发下游节点的)
public abstract class AbstractLinkedProcessorSlot<T> implements ProcessorSolt<T> {
/**
* 设置链的下一个触发的组件
*/
private AbstractLinkedProcessorSlot<T> next = null;
@Override
public void fireProcess(T param) {
if(next != null){
//触发下一个节点执行
next.process(param);
}
}
public AbstractLinkedProcessorSlot<T> getNext() {
return next;
}
public void setNext(AbstractLinkedProcessorSlot<T> next) {
this.next = next;
}
@Override
public void process(T param) {
processHandler(param);
//触发下一个节点进行
fireProcess(param);
}
/**
* 定义钩子,是业务逻辑实际处理的实现
* @param param
*/
public abstract void processHandler(T param);
}
ProcessorSlotChain
该类继承AbstractLinkedProcessorSlot同时,新增了一个addLast方法,帮助开发人员构建我们链式节点。
public abstract class ProcessorSlotChain<T> extends AbstractLinkedProcessorSlot<T> {
/**
* 添加到下一个触发节点
* @param processorSlot
*/
public abstract void addLast(AbstractLinkedProcessorSlot<T> processorSlot);
}
DefaultProcessorSlotChain
责任链的具体实现类,关键点在于初始化了一个头节点,用于触发整个链条的向下进行
public class DefaultProcessorSlotChain<T> extends ProcessorSlotChain<T> {
//初始化头检点
AbstractLinkedProcessorSlot<T> first = new AbstractLinkedProcessorSlot<T>() {
@Override
public void processHandler(T param) {
//不做处理
}
};
AbstractLinkedProcessorSlot<T> end = first;
@Override
public void processHandler(T param) {
//初始化头节点
setNext(first);
}
@Override
public void addLast(AbstractLinkedProcessorSlot<T> processorSlot) {
//设置下一个节点
end.setNext(processorSlot);
//指针就指向下一个节点
end = processorSlot;
}
}
以上实现就是最主要的类,当然还包括其他的一些类
- SlotChainBuilder 构建类
- BeforeSlotChainBuilderImpl< ProcessorSlotChain> 构建实现类
public class BeforeSlotChainBuilderImpl implements SlotChainBuilder<ProcessorSlotChain> {
@Override
public ProcessorSlotChain build() {
ProcessorSlotChain processorSlotChain = new DefaultProcessorSlotChain();
processorSlotChain.addLast(new OrderInfoSlot());
processorSlotChain.addLast(new RiskSlot());
processorSlotChain.addLast(new MarketingSlot());
return processorSlotChain;
}
}
测试
@Slf4j
public class Test {
public static void main(String[] args) {
//新建一个支付前责任链
BeforeSlotChainBuilderImpl beforeSlotChainBuilder = new BeforeSlotChainBuilderImpl();
PaymentContext context = new PaymentContext();
beforeSlotChainBuilder.build().process(context);
log.info(context.toString());
}
}
测试结果如图所示
源码参考: https://github.com/zzjmay123/springboot-votes.git
在目录chain下