责任链模式

一、概念

责任链模式的定义:使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系,将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理他为止。

特点:

  • 链上的每个对象都有机会处理请求
  • 链上的每个对象都持有下一个要处理对象的引用
  • 链上的某个对象无法处理当前请求,那么它会把相同的请求传给下一个对象
    用一张图表示以下使用了责任链模式之后的架构:
    责任链模式满足了请求发送者与请求处理者之间的松耦合,抽象非核心的部分,以链式调用的方式对请求对象进行处理。

二、应用场景

  • 多条件流程判断 权限控制
  • ERP系统 流程审批 总经理、人事经理、项目经理
  • Java过滤器的底层实现Filter

三、网关权限控制责任链模式

在这里插入图片描述

1.抽象处理者(Handler)角色:定义出一个处理请求的接口
2.具体处理者(ConcreteHandler)角色:具体处理者接到请求后,可以选择将请求处理掉,或者将请求传给下家。

在网关作为微服务程序的入口,拦截客户端所有的请求实现权限控制 ,比如先判断Api接口限流、黑名单、用户会话、参数过滤。

Api接口限流→黑名单拦截→用户会话→参数过滤

1 GatewayHandler抽象角色

public abstract class GatewayHandler {

  protected GatewayHandler nextGatewayHandler;
  /**
   * 处理业务逻辑 return true 表示继续执行 false表示不继续执行..
   */
  public abstract boolean service(Map<String,Object> param);

  public void setNextGatewayHandler(GatewayHandler gatewayHandler) {
    this.nextGatewayHandler = gatewayHandler;
  }

  //抽出一个模板:用于外部调用的入口
  public void execute(Map<String,Object> param) {
    boolean service = service(param);
    if (nextGatewayHandler != null && service) {
      nextGatewayHandler.execute(param);
    }
  }
}

2 具体Handler实现

@Component
public class CurrentLimitHandler extends GatewayHandler{

  @Override
  public boolean service(Map<String,Object> param) {
    System.out.println("第一关网关限流判断....参数="+param);
    param.put("code1","第一关网关限流判断");
    return true;
  }
}

@Component
public class BlacklistHandler extends GatewayHandler{

  @Override
  public boolean service(Map<String,Object> param) {
    System.out.println("第二关黑名单拦截判断....参数="+param);
    param.put("code2","第二关黑名单拦截判断");
    return true;
  }
}

@Component
public class ConversationHandler extends GatewayHandler {

  @Override
  public boolean service(Map<String,Object> param) {
    System.out.println("第三关用户会话拦截判断....参数="+param);
    param.put("code3","第三关用户会话拦截判断....");
    return true;
  }
}

3 FactoryHandler

public class FactoryHandler {

  public static GatewayHandler getGatewayHandler() {
    Map<String,Object> param=new HashMap<>();
    param.put("businessCode","请求参数");

    //初始化对象
    GatewayHandler gatewayHandler1 = new CurrentLimitHandler();
    GatewayHandler gatewayHandler2 = new BlacklistHandler();
    GatewayHandler gatewayHandler3 = new ConversationHandler();

    //设置引用,执行顺序设置
    gatewayHandler1.setNextGatewayHandler(gatewayHandler2);
    gatewayHandler2.setNextGatewayHandler(gatewayHandler3);
    return gatewayHandler1;
  }

  public static void main(String[] args) {
    GatewayHandler gatewayHandler = FactoryHandler.getGatewayHandler();
    Map<String,Object>  param = new HashMap<>();
    gatewayHandler.execute(param);
    System.out.println(param);
  }
}

4 基于数据库实现

相关SQL语句

CREATE TABLE `gateway_handler` (
  `ID` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `handler_name` varchar(32) DEFAULT NULL COMMENT 'handler名称',
  `handler_id` varchar(32) DEFAULT NULL COMMENT 'handler主键id',
  `prev_handler_id` varchar(32) DEFAULT NULL,
  `next_handler_id` varchar(32) DEFAULT NULL COMMENT '下一个handler',
  PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8 COMMENT='权限表';

INSERT INTO `gateway_handler` VALUES (16, 'Api接口限流', 'currentLimitHandler', NULL, 'blacklistHandler');
INSERT INTO `gateway_handler` VALUES (17, '黑名单拦截', 'blacklistHandler', 'currentLimitHandler', 'conversationHandler');
INSERT INTO `gateway_handler` VALUES (18, '会话验证', 'conversationHandler', 'blacklistHandler', NULL);

5 GatewayHandlerService

@Service
@Slf4j
public class GatewayHandlerService {
  @Autowired
  private GatewayHandlerMapper gatewayHandlerMapper;

  public GatewayHandler getGatewayHandler(Map<String,Object> param) {

    //获取头节点
    GatewayHandlerEntity firstGatewayHandler = gatewayHandlerMapper.getFirstGatewayHandler();
    if (Objects.isNull(firstGatewayHandler)) {
      log.info("未配置头节点,请注意");
      return null;
    }

    String handlerId = firstGatewayHandler.getHandlerId();
    if (StringUtils.isEmpty(handlerId)) {
      log.info("未配置头节点,请注意");
      return null;
    }

    //从容器中获取bean对象
    GatewayHandler bean = SpringBootBeanUtil.getBean(handlerId, GatewayHandler.class);
    if (Objects.isNull(bean)) {
      log.info("容器中未找到");
      return null;
    }

    //下一节点名称
    String nextHandlerId = firstGatewayHandler.getNextHandlerId();

    //记录当前对象
    GatewayHandler currentBean = bean;
    while (!StringUtils.isEmpty(nextHandlerId)) {

      //从容器获取下一个执行handler
      GatewayHandler nextBean = SpringBootBeanUtil.getBean(nextHandlerId, GatewayHandler.class);
      if (Objects.isNull(nextBean)) {
        break;
      }

      //查询db获取下一个handlerid
      GatewayHandlerEntity nextGatewayHandler = gatewayHandlerMapper.getNextGatewayHandler(nextHandlerId);
      if (Objects.isNull(nextGatewayHandler)) {
        break;
      }
      nextHandlerId = nextGatewayHandler.getNextHandlerId();

      currentBean.setNextGatewayHandler(nextBean);
      currentBean = nextBean;
    }

    return bean;
  }

}

6 SpringBootBeanUtil

获取Spring容器中的bean工具类

@Component
public class SpringBootBeanUtil implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if (SpringBootBeanUtil.applicationContext == null) {
            SpringBootBeanUtil.applicationContext = applicationContext;
        }
    }

    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    /**
     * 通过class获取Bean.
     */
    public static <T> T getBean(Class<T> clazz) {
        return getApplicationContext().getBean(clazz);
    }

    /**
     * 通过name获取 Bean.
     */
    public static Object getBean(String name) {
        return getApplicationContext().getBean(name);
    }

    /**
     * 通过name,以及Clazz返回指定的Bean
     */
    public static <T> T getBean(String name, Class<T> clazz) {
        return getApplicationContext().getBean(name, clazz);
    }
}

7 GatewayHandlerMapper

@Mapper
public interface GatewayHandlerMapper {
  /**
   * 获取第一个GatewayHandler
   */
  @Select("SELECT  handler_name AS handlerName,handler_id AS handlerid ,prev_handler_id AS prevhandlerid ,next_handler_id AS nexthandlerid  FROM gateway_handler WHERE  prev_handler_id is null;;")
  GatewayHandlerEntity getFirstGatewayHandler();

  @Select("SELECT  handler_name AS handlerName,handler_id AS handlerid ,prev_handler_id AS prevhandlerid ,next_handler_id AS nexthandlerid   FROM gateway_handler WHERE  handler_id=#{handlerId}")
  GatewayHandlerEntity getNextGatewayHandler(String handlerId);
}

8 测试

@RestController
public class GatewayController {

  @Autowired
  private GatewayHandlerService gatewayHandlerService;

  @RequestMapping("/client")
  public String client() {
    Map<String,Object>  param = new HashMap<>();
    GatewayHandler firstGatewayHandler = gatewayHandlerService.getGatewayHandler(param);
    firstGatewayHandler.execute(param);
    return param.toString();
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值