背景:
收到需求需要校验用户身份证和姓名是否匹配,要求可以顺序执行不同的校验方法,任一步返回结果,很容易想到责任链模式,网上的例子多半是原理讲解类的,没有充分使用 Spring 特点,所以记录一下。技术有限,如有纰漏,欢迎指正。
-
要求增加新的处理渠道不改动原来的代码。
-
使用 Spring 的方式编写。
重点:
- Spring 支持一次性将一个接口的所有实现类一次性载入进来
- 借用 @Order 注解 实现责任链的先后排序
- 使用 @Bean 指定名称初始化
首先,准备一个抽象类,重要的有三点,可以指定的下一个处理对象,执行控制方法,和实际校验方法。
@Data
public abstract class HandlerChain {
private HandlerChain **nextHandler**;
/**
\* 执行控制方法
\* @param person
\* @return
\*/
public CheckResultDTO handler(PersonDTO person){
CheckResultDTO result = check(person);
if (!result.getIsOver()) {
return **nextHandler**.handler(person);
}
return result;
}
/**
\* 实际校验逻辑
\* @param person
\* @return
\*/
public abstract CheckResultDTO check(PersonDTO person);
}
然后是三个实现类,@Order (0) 注解可以控制实例加载的顺序,参数越小越优先。以下均为伪代码,具体逻辑看业务需求。
@Order(0)
@Component
public class DataBaseHandler extends HandlerChain {
@Override
public CheckResultDTO check(PersonDTO person) {
//查询数据库 略。。。
boolean checkResult = false;
if (checkResult) {
return new CheckResultDTO(false,"校验未通过",true);
}
return new CheckResultDTO(false,"继续验证",false); }
}
@Order(1) @Component public class AliHandler extends HandlerChain { @Override public CheckResultDTO check(PersonDTO person) { //调用阿里的PIA 略。。。 boolean checkResult = false; if (checkResult) { return new CheckResultDTO(false,"校验未通过",true); } return new CheckResultDTO(false,"继续验证",false); } }
@Order(2) @Component public class ThirdHandler extends HandlerChain { @Override public CheckResultDTO check(PersonDTO person) { //查询第三方的API 略。。。 boolean checkResult = true; if (checkResult) { return new CheckResultDTO(false,"校验通过",true); } return new CheckResultDTO(false,"未知信息",true); } }
最后是链条组装初始化的配置:
@Configuration public class InitHandlerChain { @Autowired List**handlerChains**; @Bean(name = "firstHandler") public HandlerChain firstHandler(){ int size = **handlerChains**.size(); for (int i=0;i 其中通过 @Autowird 注入的 list 将 HandlerChain 的所有子类都注入进来,且是按照 @Order 注解规定的顺序。
调用方式:
@RestController public class CheckController { @Autowired @Qualifier("firstHandler") private HandlerChain **firstHandler**; @RequestMapping("/check") public CheckResultDTO check(PersonDTO personDTO){ CheckResultDTO handler =**firstHandler**.handler(personDTO); return handler; } }由于 @Autowired 是按照类型注入的 所以需要配合 @Qualifier 指定名称使用 此处也可使用 @Resource。