
1. 什么是责任链模式
定义:为了避免请求发送者和多个请求处理者之间的耦合,于是将所有请求的处理者通过前一对象记住其后一对象的引用。当有请求来时,可将请求沿着链传递,直到有处理者处理它为止。
如图,每个节点只负责自己处理的事情,节点1处理完了再到节点2,节点2处理完了再到节点3
优点:
降低了对象之间的耦合度,该模式使得一个对象无须知道到底是哪一个对象处理其请求。
责任链简化了对象之间的连接,每个对象只需要保持一个后继者的引用,不需要保持其他所有的处理者,避免了使用众多的if/else责任分担,每个类只处理自己该处理的工作,不该处理的传递给下一个对象完成。
2. 责任链模式的2种形式
关于责任链模式,其有两种形式:
⼀种是通过外部调⽤的⽅式对链的各个节点调⽤进⾏控制,从⽽进⾏链的各个节点之间的切换;
另⼀种是链的每个节点⾃由控制是否继续往下传递链的进度,这种⽐较典型的使⽤⽅式就是Netty中的责任链模式。
3. 责任链模式项目实战
本文以电商系统中下单操作为例子:假设某商品处于活动中,下单会经过以下校验:

商品是否还处于活动中。如果没在活动中,则不能下单了。
此商品购买的最大数量。如果下单的数量超出了最大允许购买的数量,下单失败。
哪些人能购买。此商品只能允许部分人购买,其他人不具备购买资格如果下单,将会下单失败。
此商品是否能用劵购买。此商品不能使用优惠券,使用优惠券则会下单失败。
4. 没用责任链模式的写法
我们先看看传统如何写这个校验代码,每个校验操作写一个方法,本文将会以最简单的代码去演示。
public class OrderService {public void placeOrder() {checkActive();checkPurchaseMaxCount();checkCanPurchaseByUser();checkCanUseCoupon();System.out.println("购买成功");}private void checkActive() {System.out.println("检查此商品是否还处于活动中....");System.out.println("检查通过===========");}private void checkPurchaseMaxCount() {System.out.println("检查此商品能购买的最大数量....");System.out.println("检查通过===========");}private void checkCanPurchaseByUser() {System.out.println("检查此购买用户是否有资格购买此商品....");throw new RuntimeException("检查失败,此用户不具备购买资格");}private void checkCanUseCoupon() {System.out.println("检查此商品是否能使用优惠券....");}public static void main(String[] args) {OrderService orderService = new OrderService();orderService.placeOrder();}}
5. 传统责任链模式写法
以下代码就是责任链模式中的节点控制模式,可以看到我在第一个节点里面我可以控制是否走下一个节点,对应的就是这句代码:super.handler.handle();
public abstract class IHandler {// 下一个处理器protected IHandler handler;abstract void handle();public void setHandler(IHandler handler) {this.handler = handler;}}
public class CheckActiveHandler extends IHandler{@Overridepublic void handle() {System.out.println("检查此商品是否还处于活动中....");System.out.println("检查通过===========");// 进入下一个处理器super.handler.handle();}}
public class CheckPurchaseMaxCountHandler extends IHandler{@Overridepublic void handle() {System.out.println("检查此商品能购买的最大数量....");System.out.println("检查通过===========");super.handler.handle();}}
public class CheckCanQualifiedToPurchaseHandler extends IHandler{@Overridepublic void handle() {System.out.println("检查此购买用户是否有资格购买此商品....");throw new RuntimeException("检查失败,此用户不具备购买资格");}}
public class CheckCanUseCouponHandler extends IHandler{@Overridepublic void handle() {System.out.println("检查此商品是否能使用优惠券....");}}
下单操作首先要实例化所有的handler,然后设置好顺序
public class OrderService2 {public void placeOrder() {IHandler checkActiveHandler = new CheckActiveHandler();IHandler checkCanQualifiedToPurchaseHandler = new CheckCanQualifiedToPurchaseHandler();IHandler checkCanUseCouponHandler = new CheckCanUseCouponHandler();IHandler checkPurchaseMaxCountHandler = new CheckPurchaseMaxCountHandler();// 按顺序设置下个处理器checkActiveHandler.setHandler(checkPurchaseMaxCountHandler);checkPurchaseMaxCountHandler.setHandler(checkCanQualifiedToPurchaseHandler);checkCanQualifiedToPurchaseHandler.setHandler(checkCanUseCouponHandler);checkActiveHandler.handle();System.out.println("购买成功");}public static void main(String[] args) {OrderService2 orderService = new OrderService2();orderService.placeOrder();}}
6. 责任链模式结合spring优雅实现
以下代码就是责任链模式中的外部控制模式,可以看到节点里面控制不了是否走下个节点了
public interface IHandler {void check();}
@Component@Order(1) //设置检查的顺序,这是第一个检查public class CheckActiveHandler implements IHandler {@Overridepublic void check() {System.out.println("检查此商品是否还处于活动中....");System.out.println("检查通过===========");}}
@Component@Order(2)public class CheckPurchaseMaxCountHandler implements IHandler {@Overridepublic void check() {System.out.println("检查此商品能购买的最大数量....");System.out.println("检查通过===========");}}
@Component@Order(3)public class CheckCanQualifiedToPurchaseHandler implements IHandler {@Overridepublic void check() {System.out.println("检查此购买用户是否有资格购买此商品....");throw new RuntimeException("检查失败,此用户不具备购买资格");}}
@Component@Order(4)public class CheckCanUseCouponHandler implements IHandler {@Overridepublic void check() {System.out.println("检查此商品是否能使用优惠券....");}}
spring会按order注解标识的顺序,自动注入IHandler的所有实现类,所以我们直接循环调用就可以了
@Servicepublic class OrderService3 {@Autowired //spring会按order顺序,自动注入IHandler的所有实现类private List<IHandler> handlers;public void placeOrder() {handlers.forEach(handler -> handler.check());System.out.println("购买成功");}}
7. 开源框架中责任链模式的运用
开源框架中很多精彩的地方都运用了责任链模式,让我们一起看看吧!
Spring的责任链模式运用
Spring Web 中的 HandlerInterceptor接口在web开发中非常常用,里面有preHandle()、postHandle()、afterCompletion()三个方法,实现这三个方法可以分别在调用”Controller”方法之前,调用”Controller”方法之后渲染”ModelAndView”之前,以及渲染”ModelAndView”之后执行。
public interface HandlerInterceptor {default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {return true;}default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,@Nullable ModelAndView modelAndView) throws Exception {}default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,@Nullable Exception ex) throws Exception {}}
HandlerInterceptor在责任链中充当处理者的角色,通过HandlerExecutionChain进行责任链调用。
public class HandlerExecutionChain {...@Nullableprivate HandlerInterceptor[] interceptors;private int interceptorIndex = -1;boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {HandlerInterceptor[] interceptors = getInterceptors();if (!ObjectUtils.isEmpty(interceptors)) {for (int i = 0; i < interceptors.length; i++) {HandlerInterceptor interceptor = interceptors[i];if (!interceptor.preHandle(request, response, this.handler)) {triggerAfterCompletion(request, response, null);return false;}this.interceptorIndex = i;}}return true;}void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)throws Exception {HandlerInterceptor[] interceptors = getInterceptors();if (!ObjectUtils.isEmpty(interceptors)) {for (int i = interceptors.length - 1; i >= 0; i--) {HandlerInterceptor interceptor = interceptors[i];interceptor.postHandle(request, response, this.handler, mv);}}}void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex)throws Exception {HandlerInterceptor[] interceptors = getInterceptors();if (!ObjectUtils.isEmpty(interceptors)) {for (int i = this.interceptorIndex; i >= 0; i--) {HandlerInterceptor interceptor = interceptors[i];try {interceptor.afterCompletion(request, response, this.handler, ex);}catch (Throwable ex2) {logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);}}}}}
调用的方式非常简单,即通过数组存储注册在Spring中的HandlerInterceptor,然后通过interceptorIndex作为指针去遍历责任链数组按顺序调用处理者。
mybatis使用责任链模式
Mybatis可以配置各种Plugin,无论是官方提供的还是自己定义的,Plugin和Filter类似,就在执行Sql语句的时候做一些操作。Mybatis的责任链则是通过动态代理的方式,使用Plugin代理实际的Executor类。(这里实际还使用了组合模式,因为Plugin可以嵌套代理),核心代码如下:
public class Plugin implements InvocationHandler{private Object target;private Interceptor interceptor;@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {if (满足代理条件) {return interceptor.intercept(new Invocation(target, method, args));}return method.invoke(target, args);}
//对传入的对象进行代理,可能是实际的Executor类,也可能是Plugin代理类public static Object wrap(Object target, Interceptor interceptor) {Class<?> type = target.getClass();Class<?>[] interfaces = getAllInterfaces(type, signatureMap);if (interfaces.length > 0) {return Proxy.newProxyInstance(type.getClassLoader(),interfaces,new Plugin(target, interceptor, signatureMap));}return target;}}
8. 责任链模式总结
责任链模式 , 又称为 职责链模式 ;
责任链模式定义 : 为 请求 创建一个接收该 请求对象 的 链 , 链条中每个元素都是一个对象 ;
责任链模式类型 : 行为型 ;
责任链模式 适用场景 : 
**
① 多个对象可以处理同一个请求,但具体由哪个对象处理则在运行时动态决定。
② 在请求处理者不明确的情况下向对个对象中的一个提交一个请求。
③ 需要动态处理一组对象处理请求。
责任链模式 优点 :
① 解耦 : 请求的 发送者 和 接收者 解耦 ; 接收者 是 请求的处理者 ;
② 动态组合 : 责任链 可以 动态组合 , 使用配置 设置责任链的 顺序及 是否出现 ; 可以随时对责任链排序 , 随时增加拆除责任链中的某个请求对象 ;
责任链模式 缺点 :
① 性能 : 如果 责任链 太长 , 或责任链中请求的 处理时间过长 , 可能会 影响性能 ;
② 个数 : 责任链 可能过多 ;
