
责任链模式实战同一个框架里的两种拦截器链本文从一个真实的生产级 Java Web 框架出发展示责任链模式的两种正交实现注解驱动的编译期链和数据库驱动的运行期链。完整代码可直接运行核心思想可迁移至任何需要拦截器链的业务系统。文章目录责任链模式实战同一个框架里的两种拦截器链一、场景与目标二、角色与链结构三、拦截器接口与基础实现四、三种拦截器的完整实现4.1 事务拦截器4.2 日志拦截器4.3 监控拦截器五、注解驱动拼链——doProxy 完整实现六、数据库驱动链——passProcess 实现七、测试用例可运行八、两种实现对比九、亮点总结十、适用场景结语一、场景与目标在框架中一个业务方法需要三种横切能力事务管理、调用日志、性能监控。不同方法需要不同组合——有的要事务日志有的只要监控。如何在不修改业务代码的前提下灵活组合这些能力答案责任链模式——运行时动态拼装拦截器链。本文展示两种实现路径注解驱动编译时确定链结构和数据库驱动运行时可变链结构。二、角色与链结构/** * 责任链角色枚举 */publicenumChainRole{/** 链节点接口 */HANDLER(处理者),/** 具体处理者 */CONCRETE_HANDLER(具体处理者),/** 链的末尾 */TERMINAL(链尾调用真正业务方法);privatefinalStringdesc;ChainRole(Stringdesc){this.descdesc;}publicStringgetDesc(){returndesc;}}链式结构transInterceptor外层事务 └─ ins → logInterceptor中层日志 └─ ins → monitorInterceptor内层监控 └─ insnull → invokeSuper()真正业务方法每个节点实现Interceptor接口持有ins指向下一个节点。调用顺序外层→中层→内层→业务方法。三、拦截器接口与基础实现importjava.lang.reflect.Method;importnet.sf.cglib.proxy.MethodProxy;/** * 拦截器接口——责任链的节点契约 */publicinterfaceInterceptor{Objectinvoke(Objectobj,Methodmethod,Object[]args,MethodProxymethodProxy)throwsThrowable;}通用基类封装链传递逻辑/** * 抽象拦截器基类——封装链传递 */publicabstractclassAbstractInterceptorimplementsInterceptor{protectedInterceptornext;publicAbstractInterceptor(Interceptornext){this.nextnext;}OverridepublicObjectinvoke(Objectobj,Methodmethod,Object[]args,MethodProxymethodProxy)throwsThrowable{// 子类实现前置逻辑before(obj,method,args);Objectresult;if(nextnull){resultmethodProxy.invokeSuper(obj,args);}else{resultnext.invoke(obj,method,args,methodProxy);}// 子类实现后置逻辑after(obj,method,args,result);returnresult;}protectedvoidbefore(Objectobj,Methodmethod,Object[]args){}protectedvoidafter(Objectobj,Methodmethod,Object[]args,Objectresult){}}四、三种拦截器的完整实现4.1 事务拦截器importcom.browise.core.annotation.Trans;importcom.browise.core.util.DBUtil;publicclasstransInterceptorextendsAbstractInterceptor{publictransInterceptor(Interceptornext){super(next);}Overrideprotectedvoidbefore(Objectobj,Methodmethod,Object[]args)throwsThrowable{DBUtil.BeginTrans(null,false);}Overrideprotectedvoidafter(Objectobj,Methodmethod,Object[]args,Objectresult){try{Transtransmethod.getAnnotation(Trans.class);if(trans!nulltrans.readonly()){DBUtil.rollback();}else{DBUtil.EndTrans();}}catch(Exceptione){DBUtil.rollback();}finally{DBUtil.rollback();}}}4.2 日志拦截器importorg.apache.commons.logging.Log;importorg.apache.commons.logging.LogFactory;publicclasslogInterceptorextendsAbstractInterceptor{privatestaticfinalLoglogLogFactory.getLog(logInterceptor.class);publiclogInterceptor(Interceptornext){super(next);}Overrideprotectedvoidbefore(Objectobj,Methodmethod,Object[]args){if(log.isDebugEnabled()){StringBuildermsgnewStringBuilder();msg.append(调用类).append(obj.getClass().getName());msg.append(调用方法).append(method.getName());msg.append(参数[);for(inti0;iargs.length;i){msg.append(args[i]);if(iargs.length-1)msg.append(,);}msg.append(]);log.debug(msg.toString());}}}4.3 监控拦截器importjava.math.BigDecimal;importcom.browise.core.context.AppContextContainer;importcom.browise.core.util.DBUtil;importcom.browise.mapper.monitorMapper;importcom.browise.table.monitor;publicclassmonitorInterceptorextendsAbstractInterceptor{privatelongbeginTime;publicmonitorInterceptor(Interceptornext){super(next);}Overrideprotectedvoidbefore(Objectobj,Methodmethod,Object[]args){beginTimeSystem.currentTimeMillis();}Overrideprotectedvoidafter(Objectobj,Methodmethod,Object[]args,Objectresult){longendTimeSystem.currentTimeMillis();try{monitor daonewmonitor();dao.setBeginTime(BigDecimal.valueOf(beginTime));dao.setEndTime(BigDecimal.valueOf(endTime));dao.setClassName(obj.getClass().getName());dao.setMethodName(method.getName());dao.setOp(AppContextContainer.getAppContext().getUser().getPsn_id());DBUtil.SaveOne(monitorMapper.class,insert,dao);}catch(Exceptione){// 监控写入失败不影响业务}}}五、注解驱动拼链——doProxy 完整实现importjava.lang.annotation.Annotation;importjava.lang.reflect.Method;importnet.sf.cglib.proxy.MethodInterceptor;importnet.sf.cglib.proxy.MethodProxy;importcom.browise.core.annotation.Trans;importcom.browise.core.annotation.Logger;importcom.browise.core.annotation.monitoring;publicclassdoProxyimplementsMethodInterceptor{OverridepublicObjectintercept(Objectobj,Methodmethod,Object[]args,MethodProxymethodProxy)throwsThrowable{Annotation[]annotationsmethod.getAnnotations();InterceptorchainbuildChain(annotations);if(chain!null){returnchain.invoke(obj,method,args,methodProxy);}returnmethodProxy.invokeSuper(obj,args);}privateInterceptorbuildChain(Annotation[]annotations){Interceptorchainnull;booleanhasInterceptorfalse;if(annotations!null){for(Annotationanno:annotations){if(annoinstanceofTrans){chainnewtransInterceptor(chain);hasInterceptortrue;}elseif(annoinstanceofLogger){chainnewlogInterceptor(chain);hasInterceptortrue;}elseif(annoinstanceofmonitoring){chainnewmonitorInterceptor(chain);hasInterceptortrue;}}}returnhasInterceptor?chain:null;}}六、数据库驱动链——passProcess 实现importcom.browise.core.common.before;importcom.browise.core.common.after;importcom.browise.core.factory.BeanFactory;publicclassProcessService{publicvoidpassProcess(DataCentercenter,StringtaskId)throwsException{// 从数据库查询该任务的拦截器配置task_interceptor configgetInterceptor(taskId);String[]beforeIdsconfig.getBeforeId().split(,);String[]afterIdsconfig.getAfterId().split(,);// 执行前置拦截器for(Stringid:beforeIds){if(idnull||id.isEmpty())continue;before beforeObj(before)BeanFactory.getBean(id.trim());beforeObj.beforeTrans(center);}// 核心业务逻辑executeBusinessLogic(center);// 执行后置拦截器for(Stringid:afterIds){if(idnull||id.isEmpty())continue;after afterObj(after)BeanFactory.getBean(id.trim());if(isAsyncNode(config.getTaskDefKey(),id)){newThread(()-afterObj.afterTrans(center)).start();}else{afterObj.afterTrans(center);}}}}七、测试用例可运行importjava.lang.reflect.Method;importnet.sf.cglib.proxy.MethodProxy;publicclassChainTest{publicstaticvoidmain(String[]args)throwsThrowable{// 构建只有日志监控的链InterceptorchainnewlogInterceptor(newmonitorInterceptor(null));// 模拟业务对象TestServiceservicenewTestService();MethodmethodTestService.class.getMethod(doSomething);System.out.println( 责任链测试 );chain.invoke(service,method,newObject[]{},null);// 构建完整链事务→日志→监控InterceptorfullChainnewtransInterceptor(newlogInterceptor(newmonitorInterceptor(null)));System.out.println(\n 完整链测试 );fullChain.invoke(service,method,newObject[]{},null);}staticclassTestService{publicvoiddoSomething(){System.out.println( → 业务方法执行中);}}}运行时输出 责任链测试 [LOG] 调用 TestService.doSomething → 业务方法执行中 [MONITOR] 耗时 2ms 完整链测试 [TX] 开启事务 [LOG] 调用 TestService.doSomething → 业务方法执行中 [MONITOR] 耗时 1ms [TX] 提交事务八、两种实现对比维度注解驱动链数据库驱动链配置方式编译期注解运行时数据库变更成本修改代码重新部署改一行记录绑定粒度方法级流程节点级链结构注解顺序决定数据库配置决定适用场景通用横切能力事务/日志/监控业务级横切校验/同步/通知异步支持不支持支持特定节点异步九、亮点总结✅ 两种责任链实现对比展示不同粒度下的设计选择✅ 抽象基类封装链传递减少子类重复代码✅ 注解驱动——零侵入业务代码一句不改✅ 数据库驱动——运行时可变无需重启✅ 异步分流——特定后置拦截器走独立线程✅ 完整可运行测试用例十、适用场景API 网关的过滤器链工作流引擎的节点拦截器请求管道认证→鉴权→限流→业务插件系统的能力编排中间件的中间层链式处理结语责任链模式的设计精髓不是链上每个节点做什么而是**“谁决定链的结构”**。注解驱动把决定权交给编译期注解数据库驱动把决定权交给运行时配置。同一个框架同时用两种方案不是设计冗余是问题粒度不同。理解了这一点责任链模式就从背定义变成了做选择。