责任链模式是一种设计模式。在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。
在Java中我觉得最为经典的属于,Servlet中的过滤器(Filter)和过滤器链(FilterChain)组合。
1.filter一般用于Servlet处理一些前置的校验,且给个filter有自己各自的责任和处理逻辑,在调用filter时候,需要传递filterChain,来告诉当前的执行的是那一个chain.
public interface Filter {
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException;
public default void destroy() {}
}
public interface FilterChain {
public void doFilter(ServletRequest request, ServletResponse response)
throws IOException, ServletException;
}
/**
* XSS过滤器 自定义的filter
*/
public class XSSFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// 调用下一个
chain.doFilter(new XSSRequestWrapper((HttpServletRequest) request), response);
}
}
大致处理流程:
2. 这种链路叶跟pipeline管道模式有点像,在netty中我们在设置pipeline,也是按照这个规则去设置各种handler。在我自己的项目中我是按照这个Servlet的原型进行改造的。来实现项目中前置请求的一些校验工作。
2.1:业务中有患者挂号业务,按照要求我们现有检查患者是否在医院有建档数据,没有t建档。否则还需要检查,当天是否重复挂号等。按照这个简化的需求业务我们来实现。
2.2: 基础的核心接口
public interface Filter {
//处理逻辑,
public void doFilter(FilterRequestDTO filterRequestDTO, FilterChain filterChain);
public void reset();
}
public interface FilterChain {
public void doFilter(FilterRequestDTO filterRequestDTO);
void reset();
}
public class CouponFilterChain implements FilterChain {
/**
* 责任链中的所有的处理组件 非变量
*/
private final List<? extends AbstractOrderFilter> filters;
/**
* 当前执行到的位置 这是个共享变量
*/
private static ThreadLocal<Integer> posLocal = ThreadLocal.withInitial(() -> 0);
/**
* 责任链的校验结果--即需要给用户反馈的校验结果,共享变量,threadLocal,会作为全局参数
*/
public static final ThreadLocal<List<CheckResult>> checkResult = new ThreadLocal<>();
/**
* 包含filter数量 非变量
*/
private final int size;
@Override
public void doFilter(FilterRequestDTO filterRequestDTO) {
//共享变量记住当前filterChain执行的filter的index,直至结束
Integer pos = posLocal.get();
if (pos < size) {
pos++;
posLocal.set(pos);
Filter filter = this.filters.get(pos - 1);
filter.doFilter(filterRequestDTO, this);
}
}
//供外部业务代码调用的主要方法
public List<CheckResult> process(FilterRequestDTO filterRequestDTO) {
this.doFilter(filterRequestDTO);
//将共享变量里面的结果取出来,返回给用户
return checkResult.get();
}
//注意避免ThreadLocal内存泄漏,要remove
@Override
public void reset() {
posLocal.remove();
posLocal.set(0);
checkResult.remove();
}
public CouponFilterChain(List<? extends AbstractOrderFilter> filters) {
filters.sort(AbstractOrderFilter::compareTo);
this.filters = filters;
this.size = filters.size();
}
}
定义抽象filter类
@Data
public class AbstractOrderFilter implements Filter, Comparable<AbstractOrderFilter> {
//排序字段
protected Integer order;
@Override
public int compareTo(AbstractOrderFilter abstractOrderFilter) {
return getOrder().compareTo(abstractOrderFilter.getOrder());
}
/**
* 接受
* 根据Filter自己使用的业务场景,自行定义
*
* @param filterRequestDTO 过滤请求dto
* @return boolean 返回值类型
* @author 余浪
*/
public boolean accept(FilterRequestDTO filterRequestDTO) {
return true;
}
/**
* 做过滤器
*
* @param filterRequestDTO 过滤请求dto
* @param filterChain 过滤器链
* 返回值类型
* @author 余浪
*/
@Override
public void doFilter(FilterRequestDTO filterRequestDTO, FilterChain filterChain) {
}
@Override
public void reset() {
}
}
定义两个业务filter
/**
* 挂号 过滤器
*
* @author 余浪
* @date 2023-06-14
*/
@Slf4j(topic = "checkRegisterFilter")
public class CheckRegisterFilter extends AbstractOrderFilter {
private CheckRegisterService checkRegisterService;
private CheckRegisterFilter(Integer order, CheckRegisterService checkRegisterService) {
super.order = order;
this.checkRegisterService = checkRegisterService;
}
@Override
public void doFilter(FilterRequestDTO filterRequestDTO, FilterChain filterChain) {
// 检查通过 在乎校验本次链路的逻辑
if (accept(filterRequestDTO)) {
//检查当前是否挂号
Boolean flag =
checkRegisterService.checkPatientWhetherToRegister(filterRequestDTO);
Assert.isTrue(flag,"当天重复挂号了");
}
//继续走责任链的下一个filter
filterChain.doFilter(filterRequestDTO);
}
/**
* 做自定义校验的 ,控制是否需要 执行当前链路的校验
*
* @param filterRequestDTO 过滤请求dto
* @return boolean 返回值类型
* @author 余浪
*/
@Override
public boolean accept(FilterRequestDTO filterRequestDTO) {
// 检查患者id 可以做患者身份校验等
if (StrUtil.isNotBlank(filterRequestDTO.getPatientId())) {
log.info("身份信息合法。。。 ");
return false;
}
log.info("身份信息非法 ");
//自行根据业务场景定义处理何种请求
return true;
}
//对外暴露的create方法
public static CheckRegisterFilter create(Integer order, CheckRegisterService checkRegisterService) {
return new CheckRegisterFilter(order, checkRegisterService);
}
}
/**
* 检查构建文件过滤器
*
* @author 余浪
* @date 2023-06-14
*/
@Slf4j(topic = "checkBuildFileFilter")
public class CheckBuildFileFilter extends AbstractOrderFilter {
//当前filter对应的业务逻辑manager(自行根据业务场景定义) 你自己的建档逻辑服务
private BuildFileService buildFileService;
private CheckBuildFileFilter(Integer order, BuildFileService buildFileService) {
super.order = order;
this.buildFileService = buildFileService;
}
@Override
public void doFilter(FilterRequestDTO filterRequestDTO, FilterChain filterChain) {
// 检查通过 在乎校验本次链路的逻辑
if (accept(filterRequestDTO)) {
//业务逻辑对应的manager进行校验处理(不做展开)
Boolean patientExists =
buildFileService.checkPatientExists(filterRequestDTO);
if(!patientExists){
throw new RuntimeException("用户未建档");
}
}
//继续走责任链的下一个filter
filterChain.doFilter(filterRequestDTO);
}
/**
* 做自定义校验的 ,控制是否需要 执行当前链路的校验
* @param filterRequestDTO 过滤请求dto
* @return boolean 返回值类型
* @author 余浪
*/
@Override
public boolean accept(FilterRequestDTO filterRequestDTO) {
// 身份证合法 才会去建档 ,根据自己的具体业务实现
if(StrUtil.isNotBlank(filterRequestDTO.getIdentityCardNumber())
&& IdcardUtil.isValidCard(filterRequestDTO.getIdentityCardNumber())){
log.info("身份信息合法。。。 ");
return false;
}
log.info("身份信息非法 ");
//自行根据业务场景定义处理何种请求
return true;
}
//对外暴露的create方法
public static CheckBuildFileFilter create(Integer order, BuildFileService buildFileService) {
return new CheckBuildFileFilter(order, buildFileService);
}
}
2.3: 定义FilterChainManager
@Component
@Slf4j
public class CustomFilterChainManager {
@Autowired
private BuildFileService buildFileService;
@Autowired
private CheckRegisterService checkRegisterService;
private CouponFilterChain couponFilterChain;
//初始化责任链
@PostConstruct
private void init() {
//总链
List<AbstractOrderFilter> filters = new ArrayList<>();
//按需添加链上的filter……
//商品校验filter
filters.add(CheckBuildFileFilter.create(300, buildFileService));
//门店校验filter
filters.add(CheckRegisterFilter.create(200, checkRegisterService));
this.couponFilterChain = new CouponFilterChain(filters);
}
//供外部调用的方法
public void process(FilterRequestDTO filterRequestDTO) {
try {
//责任链模式
couponFilterChain.process(filterRequestDTO);
} catch (Exception e) {
} finally {
//这里非常重要 必须重置
if (couponFilterChain != null) {
couponFilterChain.reset();
}
}
}
}
测试:
@Autowired
private CustomFilterChainManager customFilterChainManager;
@Test
public void testDemo(){
FilterRequestDTO filterRequestDTO = new FilterRequestDTO();
// 身份证号
filterRequestDTO.setIdentityCardNumber("123455");
customFilterChainManager.process(filterRequestDTO);
}
下一章节