01 什么是责任链模式
▐ 概念
责任链模式让多个对象都有机会处理同一个请求。它将请求的发送者和处理者之间进行解耦,同时将这些处理者对象连成一条链,并沿着这条链传递该请求,满足条件的处理者会执行相应的逻辑直至走完整个链条;
▐ 应用场景
如果在一次请求中,需要多个处理者处理多种复杂的逻辑,且希望能够解耦多个处理者,实现高扩展性,可以考虑使用责任链模式。
02 Servlet中的过滤器(Filter)和过滤器链(FilterChain)
▐ 概念
public interface Filter { //初始化方法 public void init(FilterConfig filterConfig) throws ServletException; //处理逻辑, public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException; //生命周期销毁 public void destroy(); }
【FilterChain】是由多个Filter组成的链条,如果在链上的filter校验通过或处理完成,那么调用"chain.doFilter(request, response)"就可以让下一个filter继续执行逻辑直到filterChain结束
public interface FilterChain { public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException; }
▐ 在Servlet中的拦截过程
请求资源时,过滤器链中的过滤器依次对请求进行处理,并将请求传递给下一个过滤器,直到最后将请求传递给目标资源。发送响应信息时,则按照相反的顺序对响应进行处理,直到将响应返回给客户端;
▐ 启发
03 业务场景应用案例
▐ 业务场景
在电商平台的很多业务场景下,涉及到对于数据的多重校验或多重过滤等操作。而随着业务的增长,校验逻辑或者数据处理逻辑会变得越来越复杂,这个时候责任链模式就能够体现出很好的优势了。
拿创建优惠券活动来举例;用户可以自由选择某些类目、某些商品或者某些门店来参与券活动;并且可以按需导入或者选择自己需要参与活动的数据;
【系统需要校验用户上传的数据是否满足业务条件、并将校验失败的数据返回给客户】
▐ 复杂点
根据上述业务场景,在一次请求中,我们需要做多种校验逻辑:
-
数据鉴权校验、过滤用户无权限的数据
-
若用户选择商品,需对商品类型进行校验;(电商的商品模型有很多种,每一种商品模型都对应一种校验规则)
-
若用户选择门店,需对门店类型进行校验;(电商的门店类型也有很多,比如线上门店、旗舰店、线下门店等等,需要判断门店是否能够参与优惠活动)
-
对于不同投放渠道也有不同渠道的校验规则
-
我们需要完整的走完所有校验逻辑,而不能因为中途的一个逻辑校验不通过而阻断校验,因为我们需要返回给用户一个完整的数据校验结果;举个例子,如果用户上传的商品当中,既存在无权限的商品,又存在不符合商品类型的数据,那么我们需要走完所有校验逻辑,一并给用户返回所有的报错,而不是只返回无权限的商品;
-
其他校验规则……
-
如果不使用设计模式
//校验数据 if (用户选择商品) { if (商品模型一) { //校验逻辑1 } else if (商品模型二) { //校验逻辑2 } else if (商品模型三) { //校验逻辑3 } else { //校验逻辑4 } } else if (用户选择门店) { if (门店模型一) { //校验逻辑1 } else if (门店模型二) { //校验逻辑2 } //校验逻辑…… } else if (用户选择类目) { //校验逻辑…… } //校验渠道 if (渠道是A渠道){ } else if (渠道是B渠道){ }
-
如果使用责任链模式
▐ 使用责任链模式+改进 [业务代码均做了简化处理]
参照Servlet的filter与filterChain接口【见2.1】,自己实现了多种不同的过滤器,也在其基础上结合业务需求进行了相应的改进:
-
定义AbstractOrderFilter抽象类
让Filter对象具备顺序属性,初始化FilterChain的时候,可以按顺序排列filter;同时定义accept方法,让filter自行控制是否处理请求。
@Data public abstract class AbstractOrderFilter implements Filter, Comparable<AbstractOrderFilter> { protected Integer order; @Override public int compareTo(AbstractOrderFilter o) { return getOrder().compareTo(o.getOrder()); } //根据Filter自己使用的业务场景,自行定义 public boolean accept(FilterRequestDTO filterRequestDTO) { return true; } @Override public void doFilter(FilterRequestDTO filterRequestDTO, FilterChain filterChain) { } }
-
继承AbstractOrderFilter,遵守单一职责原则,实现多种Filter
@Data public abstract class AbstractOrderFilter implements Filter, Comparable<AbstractOrderFilter> { protected Integer order; @Override public int compareTo(AbstractOrderFilter o) { return getOrder().compareTo(o.getOrder()); } //根据Filter自己使用的业务场景,自行定义 public boolean accept(FilterRequestDTO filterRequestDTO) { return true; } @Override public void doFilter(FilterRequestDTO filterRequestDTO, FilterChain filterChain) { } }
-
定义CouponFilterChain实现filterChain接口,定义对于内部filter的处理逻辑
-
【filters】是filterChain当中的filter集合; -
【posLocal】是一个ThreadLocal变量,记录着当前filterChain执行到了第几个filter的index; -
【checkResult】也是一个ThreadLocal变量,它记录着全局所有Filter的校验结果,每执行一个filter,filter就会把当前的执行结果记录在该变量中,之后会统一返回给用户,大大减少了参数的传递复杂度;
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 BaseResult<CheckResult> process(FilterRequestDTO filterRequestDTO) { this.doFilter(filterRequestDTO); //将共享变量里面的结果取出来,返回给用户 return BaseResult.makeSuccess(checkResult.get();); } @Override //注意避免ThreadLocal内存泄漏,要remove 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
在实现好了Filter已经FilterChain之后,我们需要对他们进行初始化,这个时候就可以根据你所需要的业务场景自行组装filter到filterChain当中; 有多种初始化方法,下面只简单介绍一种(将商品filter和门店filter初始化)
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 BaseResult<CheckResult> process(FilterRequestDTO filterRequestDTO) { this.doFilter(filterRequestDTO); //将共享变量里面的结果取出来,返回给用户 return BaseResult.makeSuccess(checkResult.get();); } @Override //注意避免ThreadLocal内存泄漏,要remove 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(); } }
到此我们已经实现了责任链模式,可以画个图理解一下:
-
拓展--组合过滤器CompositeFilter + FilterChain
/** * 合成的过滤器,改过滤器内部由多个过滤器组合而成 */ public class CompositeFilter extends AbstractOrderFilter { /** * 所有的责任事件 */ private List<? extends AbstractOrderFilter> filters = new ArrayList(); public CompositeFilter(Integer order, List<? extends AbstractOrderFilter> filters) { super.order = order; this.filters = filters; } @Override public void doFilter(FilterRequestDTO filterRequestDTO, FilterChain filterChain) { (new InnerFilterChain(filterChain, this.filters)).doFilter(filterRequestDTO); } /** * 内部链处理逻辑,优先将合成过滤器的内部过滤器进行处理,然后再传给下一个过滤器 */ private static class InnerFilterChain implements FilterChain { private final FilterChain originalChain; private final List<? extends AbstractOrderFilter> additionalFilters; private int currentPosition = 0; public InnerFilterChain(FilterChain chain, List<? extends AbstractOrderFilter> additionalFilters) { this.originalChain = chain; this.additionalFilters = additionalFilters; } @Override public void doFilter(FilterRequestDTO filterRequestDTO) { if (this.currentPosition >= this.additionalFilters.size()) { //如果已经执行完了内部过滤器,则跳到外部继续执行外部下一个节点的过滤器 this.originalChain.doFilter(filterRequestDTO); } else { //继续执行内部过滤器 this.currentPosition++; AbstractOrderFilter currentFilter = this.additionalFilters.get(this.currentPosition - 1); currentFilter.doFilter(filterRequestDTO, this); } } @Override public void reset() { } } public static CompositeFilter create(Integer order, List<? extends AbstractOrderFilter> filters) { filters.sort(AbstractOrderFilter::compareTo); return new CompositeFilter(order, filters); } }
04 思考
本文仅供学习!所有权归属原作者。侵删!文章来源: 大淘宝技术 -黄维杰(水沐) :http://mp.weixin.qq.com/s/eIxFizo6dokG5kcTslZhmQ
文章评论