什么是责任链
责任链模式是一种行为设计模式, 允许你将请求沿着处理者链进行发送。收到请求后, 每个处理者均可对请求进行处理, 或将其传递给链上的下个处理者。
使用场景
责任链的使用场景还是比较多的:
-
多条件流程判断:权限控制
-
ERP 系统流程审批:总经理、人事经理、项目经理
-
Java 过滤器的底层实现 Filter
如果不使用该设计模式,那么当需求有所改变时,就会使得代码臃肿或者难以维护
责任链设计
-
抽象处理者(Handler)角色: 定义一个处理请求的接口,包含抽象处理方法和一个后继连接。
-
具体处理者(Concrete Handler)角色: 实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
-
客户类(Client)角色: 创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。
代码片段
把这个关系维护到配置文件中或者一个枚举中。使用枚举动态的配置请求链并且将每个请求者形成一条调用链。以下通过统一网关demo来列举示例
public enum GatewayEnum {
API_HANDLER(new GatewayEntity(1, "接口限流", "com.lyk.handler.ApiLimitGatewayHandler", null, 2)),
BLACKLIST_HANDLER(new GatewayEntity(2, "黑名单拦截", "com.lyk.handler.BlacklistGatewayHandler", 1, 3)),
PARSE_HANDLER(new GatewayEntity(3, "请求解析", "com.lyk.handler.ParseGatewayHandler", 2, 4)),
ROUTE_HANDLER(new GatewayEntity(4, "路由转发", "com.lyk.handler.RouteGatewayHandler", 3, null));
final GatewayEntity gatewayEntity;
public GatewayEntity getGatewayEntity() {
return gatewayEntity;
}
GatewayEnum(GatewayEntity gatewayEntity) {
this.gatewayEntity = gatewayEntity;
}
}
实体类
public class GatewayEntity {
// 拦截者名称
private String name;
// 全限定类名
private String conference;
// ID
private Integer handlerId;
// 上一个ID
private Integer preHandlerId;
// 下一个ID
private Integer nextHandlerId;
}
处理接口
public interface GatewayDao {
/**
* 根据 handlerId 获取配置项
*
* @param handlerId
* @return
*/
GatewayEntity getGatewayEntity(Integer handlerId);
/**
* 获取第一个处理者
*
* @return
*/
GatewayEntity getFirstGatewayEntity();
}
处理接口实现
public class GatewayImpl implements GatewayDao {
/**
* 初始化,将枚举中配置的handler初始化到map中,方便获取
*/
private static final Map<Integer, GatewayEntity> gatewayEntityMap = new HashMap<>();
static {
GatewayEnum[] values = GatewayEnum.values();
for (GatewayEnum value : values) {
GatewayEntity gatewayEntity = value.getGatewayEntity();
gatewayEntityMap.put(gatewayEntity.getHandlerId(), gatewayEntity);
}
}
@Override
public GatewayEntity getGatewayEntity(Integer handlerId) {
return gatewayEntityMap.get(handlerId);
}
@Override
public GatewayEntity getFirstGatewayEntity() {
for (Map.Entry<Integer, GatewayEntity> entry : gatewayEntityMap.entrySet()) {
GatewayEntity value = entry.getValue();
// 没有上一个handler的就是第一个
if (value.getPreHandlerId() == null) {
return value;
}
}
return null;
}
}
hander枚举工厂
public class GatewayHandlerEnumFactory {
private static GatewayDao gatewayDao = new GatewayImpl();
// 提供静态方法,获取第一个handler
public static GatewayHandler getFirstGatewayHandler() {
GatewayEntity firstGatewayEntity = gatewayDao.getFirstGatewayEntity();
GatewayHandler firstGatewayHandler = newGatewayHandler(firstGatewayEntity);
if (firstGatewayHandler == null) {
return null;
}
GatewayEntity tempGatewayEntity = firstGatewayEntity;
Integer nextHandlerId = null;
GatewayHandler tempGatewayHandler = firstGatewayHandler;
// 迭代遍历所有handler,以及将它们链接起来
while ((nextHandlerId = tempGatewayEntity.getNextHandlerId()) != null) {
GatewayEntity gatewayEntity = gatewayDao.getGatewayEntity(nextHandlerId);
GatewayHandler gatewayHandler = newGatewayHandler(gatewayEntity);
tempGatewayHandler.setNext(gatewayHandler);
tempGatewayHandler = gatewayHandler;
tempGatewayEntity = gatewayEntity;
}
// 返回第一个handler
return firstGatewayHandler;
}
/**
* 反射实体化具体的处理者
*
* @param firstGatewayEntity
* @return
*/
private static GatewayHandler newGatewayHandler(GatewayEntity firstGatewayEntity) {
// 获取全限定类名
String className = firstGatewayEntity.getConference();
try {
// 根据全限定类名,加载并初始化该类,即会初始化该类的静态段
Class<?> clazz = Class.forName(className);
return (GatewayHandler) clazz.newInstance();
} catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
e.printStackTrace();
}
return null;
}
抽象handler
public abstract class GatewayHandler {
/**
* 下一关用当前抽象类来接收
*/
protected GatewayHandler next;
public void setNext(GatewayHandler next) {
this.next = next;
}
public abstract void handler();
}
责任者实现类
public class ParseGatewayHandler extends GatewayHandler {
@Override
public void handler() {
System.out.println("请求解析开始");
if (this.next != null) {
this.next.handler();
}
}
}
客户端调用
public class GetewayClient {
public static void main(String[] args) {
GatewayHandler firstGetewayHandler = GatewayHandlerEnumFactory.getFirstGatewayHandler();
firstGetewayHandler.handler();
}
}