责任链模式

什么是责任链模式

哈喽,大家好,我是花臂,今天给大家讲一下责任链模式的案例实战。

客户端发出一个请求,链上的对象都有机会来处理这一请求,而客户端不需要知道谁是具体的处理对象。这样就实现了请求者和接受者之间的解耦,并且在客户端可以实现动态的组合职责链。使编程更有灵活性。

主要特点:

  1. 有多个对象共同对一个任务进行处理
  2. 这些对象使用链式存储结构,形成一个链,每个对象知道自己的下一个对象。
  3. 一个对象对任务进行处理,可以添加一些操作后将对象传递给下一个任务。也可以在此对象上结束任务的处理,并结束任务。

主要角色:

  1. 抽象处理者(Handler)角色:定义出一个处理请求的接口。如果需要,接口可以定义 出一个方法以设定和返回对下家的引用。这个角色通常由一个Java抽象类或者Java接口实现。
  2. 具体处理者(ConcreteHandler)角色:具体处理者接到请求后,可以选择将请求处理掉,或者将请求传给下家。由于具体处理者持有对下家的引用,因此,如果需要,具体处理者可以访问下家

责任链的应用场景

  1. 多条件流程判断,权限控制
  2. ERP系统的流程审批 总经理、人事经理、项目经理
  3. java过滤器底层实现Filter,比如:在Java过滤器中客户端发送请求到服务器端,过滤会经过参数过滤、session过滤、表单过滤、隐藏过滤、检测请求头过滤

具体代码

通过责任链模式实现一个请求过滤器,依次是 api限流->黑名单拦截->session检测

基于FactoryHandler实现责任链模式

!pom文件

  <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.1.RELEASE</version>
    </parent>
    <dependencies>
        <!-- sprinboot web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.10</version>
        </dependency>
        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.6</version>
        </dependency>

!GatewayHandler抽象角色

public abstract class GatewayHandler {
 //下一个handler
 protected GatewayHandler nextgatewayHandler;

 public void setNextgatewayHandler(GatewayHandler nextgatewayHandler) {
  this.nextgatewayHandler = nextgatewayHandler;
 }
 //处理方案
 public abstract  void service();

 //执行下一关
 protected void nextService(){
if(nextgatewayHandler!=null){
 nextgatewayHandler.service();
}
}
}

!具体handler角色1

public class CurrentLimitingHander extends GatewayHandler {
 @Override
 public void service() {
  System.out.println("第一关>>>限流网关");
nextService();//执行下一关
 }

}

!具体handler角色2

public class BlacklistHandler extends GatewayHandler {
 @Override
 public void service() {
  System.out.println("第二关>>>黑名单拦截");
nextService();//执行下一关
 }
}

!具体handler角色3

public class ConversationHandler extends GatewayHandler {
 @Override
 public void service() {
  System.out.println("第三关>>>session检测");

 }

!FactoryHandler角色

 public static GatewayHandler getGatwayHandler(){
  //第一关
  GatewayHandler gatewayHandler1 = new CurrentLimitingHander();
  //第二关
  GatewayHandler gatewayHandler2 = new BlacklistHandler();
  gatewayHandler1.setNextgatewayHandler(gatewayHandler2);
  //第三关
  GatewayHandler gatewayHandler3 = new ConversationHandler();
  gatewayHandler2.setNextgatewayHandler(gatewayHandler3);
  return  gatewayHandler1;
 }

!controller

@RestController
public class HandlerMapping {

 @RequestMapping("/dd")
 public void dd() {
  GatewayHandler gatwayHandler = HandlerFactory.getGatwayHandler();
  gatwayHandler.service();
 }

测试一

基于数据库实现责任链模式

建表

DROP TABLE IF EXISTS `gateway_handler`;
CREATE TABLE `gateway_handler`  (
  `ID` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `handler_name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT 'handler名称',
  `handler_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT 'handler主键id',
  `prev_handler_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
  `next_handler_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '下一个handler',
  PRIMARY KEY (`ID`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 19 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '权限表' ROW_FORMAT = Dynamic;

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

修改pom文件

 <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.1.1</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

修改具体handler角色

将他们注入到spring容器中

@Component
public class CurrentLimitingHander extends GatewayHandler {
 @Override
 public void service() {
  System.out.println("第一关>>>限流网关");
nextService();//执行下一关
 }

}
@Component
public class BlacklistHandler extends GatewayHandler {

 @Override
 public void service() {
  System.out.println("第二关>>>黑名单拦截");
nextService();//执行下一关
 }
}
@Component
public class ConversationHandler extends GatewayHandler {
 @Override
 public void service() {
  System.out.println("第三关>>>会话拦截");

 }
}

mapper

public interface HandlerMapper {

 /**
  * 获取第一个GatewayHandler
  *
  * @return
  */
 @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;;")
 public 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}")
 public GatewayHandlerEntity getByHandler(String handlerId);

}

service

@Service
public class GatewayService {

 @Autowired
 private HandlerMapper handlerMapper;

 private GatewayHandler firstGatewayHandler;

 public GatewayHandler getGatwayHandler() {
  if (this.firstGatewayHandler != null) {
   return firstGatewayHandler;

  }
  //从数据库中查询出第一个handler
  GatewayHandlerEntity firstGatewayHandler = handlerMapper.getFirstGatewayHandler();
  if (firstGatewayHandler == null) {
   return null;
  }
//根据容器id获取对象
  String handlerId = firstGatewayHandler.getHandlerId();
  GatewayHandler firstgatewayHandler = SpringUtils.getBean(handlerId, GatewayHandler.class);

  //获取下一个handler
  String nextHandlerId = firstGatewayHandler.getNextHandlerId();
  //记录当前循环的handler对象
  GatewayHandler gatewayHandler = firstgatewayHandler;
  while (!StringUtils.isEmpty(nextHandlerId)) {
   //根据bean id从 spring容器中获取下一个handler
   GatewayHandler nextgatewayHandler = SpringUtils.getBean(nextHandlerId, GatewayHandler.class);
   gatewayHandler.setNextgatewayHandler(nextgatewayHandler);

   //设置下一个nextHandlerid
   GatewayHandlerEntity gatewayHandlerEntity = handlerMapper.getByHandler(nextHandlerId);
   if (gatewayHandlerEntity == null) {
    break;
   }
   nextHandlerId = gatewayHandlerEntity.getNextHandlerId();
   gatewayHandler = nextgatewayHandler;
  }
  this.firstGatewayHandler = firstgatewayHandler;
  return firstgatewayHandler;
 }
}

bean工具类

利用 bean 的 id 通过这个工具类将 spring 容器中的对象取出来

@Component
public class SpringUtils implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

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

    //获取applicationContext
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

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

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

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

}

pojo实体类

@Data
public class GatewayHandlerEntity implements Serializable, Cloneable {
    /**
     * 主键ID
     */
    private Integer id;
    /**
     * handler名称
     */
    private String handlerName;
    /**
     * handler主键id
     */
    private String handlerId;
    /**
     * 下一个handler
     */
    private String nextHandlerId;

}

controller层

@RestController
public class HandlerMapping {

 @Autowired
 private GatewayService gatewayService;

 @RequestMapping("/ddd")
 public void ddd() {
  GatewayHandler gatwayHandler = gatewayService.getGatwayHandler();
  gatwayHandler.service();
 }

}

测试二

ok.本次教程就到这儿,有什么疑问,欢迎下方评论区留言!

本文参考蚂蚁课堂

评论区



© [2020] · Powered by Typecho · Theme by Morecho
鄂ICP备20005123号