资讯详情

13-A-责任链模式详解

📅 2026/10/18 1:56:28 | 华诺云谱 👁 阅读
13-A-责任链模式详解
13-A-责任链模式详解关键词责任链、下单校验链、Filter、Netty Pipeline、Ordered、快速失败责任链模式解决一个问题一个请求要经过一串处理环节每个环节决定处理、传递还是中断。下单前的库存校验、限购校验、风控校验、价格校验——环节会增减、顺序有讲究、有的场景要跳过某些环节责任链让这些可插拔。 术语速查表术语人话解释处理器Handler链上的一个环节处理或传递给下一个链Chain处理器的有序串联快速失败任一环节拒绝就立刻中断返回校验类场景全量收集所有环节都跑完汇总结果体检类场景supports环节自己声明这个请求归不归我管OrderedSpring 的排序接口值越小越先执行一、不用责任链的问题// ❌ 校验逻辑堆在一个方法里每加一种校验就改这个方法publicvoidvalidate(OrderRequestreq){if(inventoryNotEnough(req))thrownewBizException(库存不足);if(exceedPurchaseLimit(req))thrownewBizException(超出限购);if(riskHit(req))thrownewBizException(风控拦截);if(priceChanged(req))thrownewBizException(价格已变动);// 新需求海外单要加海关校验——继续往这里塞方法奔着 300 行去了}痛点新增/删除/调整环节都要改同一个方法不同订单类型普通/秒杀/海外要走不同校验组合时方法里全是 if单个校验无法独立测试和复用。二、模式结构通过通过通过拒绝拒绝下单请求库存校验限购校验风控校验价格校验进入建单中断返回三、业务场景下单校验链处理器接口publicinterfaceOrderValidator{/** 执行顺序值越小越先执行间隔 100 留出插入空间 */intorder();/** 这个请求归不归我管海外单才走海关校验 */defaultbooleansupports(OrderContextctx){returntrue;}/** 校验通过返回 null拒绝返回错误信息 */ValidateResultvalidate(OrderContextctx);}/** 上下文承载请求数据 缓存中间结果避免每个环节重复查库 */publicclassOrderContext{privatefinalOrderRequestrequest;privatefinalMapString,ObjectcachenewHashMap();publicOrderContext(OrderRequestrequest){this.requestrequest;}publicOrderRequestgetRequest(){returnrequest;}SuppressWarnings(unchecked)publicTTcacheGet(Stringkey,SupplierTloader){return(T)cache.computeIfAbsent(key,k-loader.get());}}具体处理器ComponentpublicclassInventoryValidatorimplementsOrderValidator{privatefinalInventoryServiceinventoryService;Overridepublicintorder(){return100;}// 库存最先校验OverridepublicValidateResultvalidate(OrderContextctx){// 查询结果放上下文缓存——后面的环节限购也要用 SKU 信息不重复查ListSkuStockstocksctx.cacheGet(stocks,()-inventoryService.batchQuery(ctx.getRequest().getSkuIds()));for(SkuStocks:stocks){if(s.getAvailable()ctx.getRequest().getCount(s.getSkuId())){returnValidateResult.reject(库存不足: s.getSkuId());}}returnValidateResult.pass();}}ComponentpublicclassPurchaseLimitValidatorimplementsOrderValidator{Overridepublicintorder(){return200;}OverridepublicValidateResultvalidate(OrderContextctx){// 秒杀单限购更严格intlimitctx.getRequest().isSeckill()?1:5;intboughtctx.cacheGet(bought,()-orderDao.countTodayBought(ctx.getRequest().getUserId(),ctx.getRequest().getSkuIds()));returnboughtlimit?ValidateResult.reject(超出限购数量):ValidateResult.pass();}}ComponentpublicclassCustomsValidatorimplementsOrderValidator{Overridepublicintorder(){return350;}Overridepublicbooleansupports(OrderContextctx){returnctx.getRequest().isCrossBorder();// 只有跨境单走海关校验}OverridepublicValidateResultvalidate(OrderContextctx){// 身份证信息、年度额度校验...returnValidateResult.pass();}}链执行器Spring 自动收集 排序ComponentpublicclassOrderValidateChain{privatefinalListOrderValidatorvalidators;publicOrderValidateChain(ListOrderValidatorvalidators){// Spring 注入所有实现按 order 排序——新增校验器零改动this.validatorsvalidators.stream().sorted(Comparator.comparingInt(OrderValidator::order)).toList();log.info(下单校验链装配完成: {},this.validators.stream().map(v-v.getClass().getSimpleName()).toList());}/** 快速失败模式任一环节拒绝立即返回 */publicValidateResultdoValidate(OrderContextctx){for(OrderValidatorv:validators){if(!v.supports(ctx))continue;ValidateResultrv.validate(ctx);if(!r.isPass()){log.warn(校验拒绝 by {}: {},v.getClass().getSimpleName(),r.getMsg());returnr;}}returnValidateResult.pass();}/** 全量收集模式跑完所有环节一次告诉用户全部问题表单校验体验更好 */publicListValidateResultvalidateAll(OrderContextctx){returnvalidators.stream().filter(v-v.supports(ctx)).map(v-v.validate(ctx)).filter(r-!r.isPass()).toList();}}调用方ServicepublicclassOrderFacade{publicOrderResultplaceOrder(OrderRequestreq){ValidateResultvrvalidateChain.doValidate(newOrderContext(req));if(!vr.isPass()){returnOrderResult.reject(vr.getMsg());}// ... 后续建单流程}}四、责任链的三种形态形态传递方式典型例子纯责任链每个 Handler 持有 next 引用自己决定传不传NettyChannelPipeline、Servlet Filter集合遍历式本文执行器 for 循环遍历Handler 不感知链SpringHandlerInterceptor、业务校验链管道式Pipeline前一个的输出是后一个的输入Stream 操作、数据 ETL 管道Servlet Filter 的纯责任链写法next 在 Handler 手里publicinterfaceFilter{voiddoFilter(Requestreq,Responseresp,FilterChainchain);}// 每个 Filter 自己决定chain.doFilter(...) 继续或不调用即中断五、框架中的同款实现框架应用说明ServletFilterChain最经典的责任链每个 Filter 决定是否放行Spring MVCHandlerInterceptor链preHandle 返回 false 即中断NettyChannelPipelineChannelHandler双向责任链inbound/outbound性能极致DubboFilter链监控/限流/鉴权全是链上环节Spring SecuritySecurityFilterChain十几个安全过滤器按序执行MyBatis插件Interceptor链分页插件 PageHelper 就是链上一环OkHttpInterceptor链重试→桥接→缓存→连接→网络教科书级管道六、常见误用与生产事故误用一顺序靠类名排序或注入顺序不写order()指望 Spring 注入 List 的顺序——注入顺序受包扫描顺序影响不同机器/不同重启可能不同。风控校验排到了库存校验后面看似无害但限购在风控前意味着被风控拉黑的用户还能触发限购计数数据被污染。纪律顺序必须显式Ordered/Order/自定义order()且启动时打印装配好的链顺序上面代码里的 log.info让顺序可见、可 review。误用二环节之间有隐式依赖PriceValidator依赖InventoryValidator往上下文里放的stocks缓存——但这个依赖没有任何声明有人调整 order 把价格校验挪到库存前面线上 NPE。防御上下文取值用cacheGet(key, loader)——取不到就自己加载不依赖别人放过有硬依赖的环节用dependsOn()显式声明装配时做拓扑校验依赖方 order 必须更小否则启动失败。事故全量收集模式里一个环节抛异常整条链崩了表单校验用validateAll某个校验器依赖的营销服务超时抛异常——整个下单接口 500。其实这个校验是锦上添花优惠券可用性预检挂了应该跳过而不是拒绝服务。修复环节分级强校验库存/风控异常拒绝与弱校验体验类异常跳过并告警执行器对弱校验 try-catch异常时按配置的降级策略处理每个环节加耗时和异常打点——哪个环节慢/挂了监控一眼看到。七、责任链 vs 策略最高频混淆维度责任链策略执行几个都过一遍串联选一个互斥环节关系有顺序、可中断平等、可互换判断口诀“这些逻辑是流水线吗”“这些逻辑是二选一吗”下单校验库存限购风控都要过→ 责任链计费方式按单/按月/按量选一种→ 策略。详见 21-A-策略模式详解。八、总结责任链的核心请求沿一串处理器传递每个环节决定处理/传递/中断——环节可插拔、顺序可管理。设计五要点顺序显式化order 间隔留余量、supports 条件过滤、快速失败与全量收集两种模式、上下文对象承载数据与缓存、每环节可开关可观测。三种形态纯责任链next 在 Handler 手里Filter/Netty、集合遍历式业务校验链首选、管道式输出即输入。生产纪律启动打印链顺序环节依赖显式声明强弱校验分级弱校验异常降级不崩链。与策略的分界都过一遍是链选一个是策略。上一篇12-A-代理模式详解下一篇14-A-命令模式详解
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑