Java的责任链模式在项目中的使用

[复制链接]
发表于 2025-11-16 09:02:55 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
        责任链模式(Chain of Responsibility Pattern)是一种举动计划模式,它允许通过多个处理处罚对象来转达哀求,直到一个处理处罚对象处理处罚该哀求为止。责任链模式的告急长处是可以解耦哀求发送者和哀求吸收者,客户端无需明确指定哪个对象负责处理处罚哀求,只须要将哀求转达给链中的第一个处理处罚对象即可。
责任链模式的应用场景:


  • 哀求处理处罚的多个阶段:当一个哀求须要多个处理处罚步调时,每个步调可以作为责任链中的一个节点举行处理处罚。
  • 哀求处理处罚次序不固定:哀求的处理处罚次序不固定,详细由体系的须要来决定,通常由责任链中的对象决定是否继续转达哀求。
  • 链中对象可动态添加:责任链中的处理处罚对象可以动态调解。

Spring Web MVC (HandlerInterceptor)

HandlerInterceptor 是一个非常有用的接口,它允许我们在哀求到达 Controller 之前和之后,乃至在视图渲染之后实验一些处理处罚。HandlerInterceptor 是基于责任链模式(Chain of Responsibility Pattern)实现的,多个拦截器可以按次序实验,每个拦截器可以在哀求的生命周期中实验差别的任务。

  • preHandle:哀求到达 Controller 之前调用,通常用于举行权限查抄、日志日志记录等操纵。如果返回 false,哀求将克制,后续的拦截器和 Controller 不会被实验。
  • postHandle:哀求完成 Controller 实验后,视图渲染之前调用。可以用于在视图渲染之前对模子数据举行处理处罚(比方,修改模子数据或添加属性等)。
  • afterCompletion:视图渲染完成后调用,可以用于整理资源(比方,关闭数据库毗连,日志日志记录等)。
  1. public interface HandlerInterceptor {
  2.     // 在Controller处理请求之前进行调用
  3.     boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
  4.     // 在Controller处理请求之后,视图渲染之前调用
  5.     void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception;
  6.     // 视图渲染完成之后进行调用
  7.     void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception;
  8. }
复制代码
怎样在 Spring MVC 中使用 HandlerInterceptor

1. 创建自界说的 HandlerInterceptor 实现

起首,我们须要实现 HandlerInterceptor 接口,并重写 preHandle、postHandle 和 afterCompletion 方法。比方:
  1. import org.springframework.web.servlet.HandlerInterceptor;
  2. import javax.servlet.http.HttpServletRequest;
  3. import javax.servlet.http.HttpServletResponse;
  4. public class MyInterceptor implements HandlerInterceptor {
  5.     // 在Controller之前执行
  6.     @Override
  7.     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
  8.         System.out.println("Pre Handle: Request intercepted before reaching the Controller");
  9.         // 返回true表示继续处理请求,返回false表示请求被拦截,不再传递给Controller
  10.         return true;
  11.     }
  12.     // 在Controller之后,视图渲染之前执行
  13.     @Override
  14.     public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
  15.                            ModelAndView modelAndView) throws Exception {
  16.         System.out.println("Post Handle: Request intercepted after the Controller has finished processing");
  17.     }
  18.     // 视图渲染完成之后执行
  19.     @Override
  20.     public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
  21.         System.out.println("After Completion: Request has completed, used for cleanup");
  22.     }
  23. }
复制代码
2. 拦截器链的次序

如果注册了多个拦截器,拦截器会按照注册次序实验 preHandle 方法,而且按相反次序实验 afterCompletion 方法。比方:
  1. @Configuration
  2. public class WebConfig implements WebMvcConfigurer {
  3.     @Override
  4.     public void addInterceptors(InterceptorRegistry registry) {
  5.         registry.addInterceptor(new MyInterceptor1()).addPathPatterns("/**");
  6.         registry.addInterceptor(new MyInterceptor2()).addPathPatterns("/**");
  7.     }
  8. }
复制代码
MyInterceptor1 的 preHandle 会在 MyInterceptor2 的 preHandle 之前实验,afterCompletion 会按相反次序实验。preHandle就构成了一条责任链,afterCompletion又是一条责任链。
常见用途


  • 权限验证:可以使用 preHandle 查抄哀求是否具有正当的权限(比方用户是否登录)。
  • 日志日志记录:使用 preHandle 记录哀求的 URL 和时间,使用 postHandle 记录相应结果。
  • 性能监控监控:通过 preHandle 和 postHandle 盘算哀求处理处罚的时间。
  • 修改模子数据:在 postHandle 中修改 ModelAndView,比如添加全局的属性或对模子数据举行修改。
  • 整理工作:在 afterCompletion 中举行整理工作,比如开释数据库毗连、线程池资源等。

开发中责任链的运用

1.校验参数

         在创建商品信息的时间须要去校验很多的各种各样的信息,而且每次须要增长新的条件都须要去修改代码(不符合软件计划的开闭原则):
  1. public void createGoods(GoodsSaveReqDTO requestParam) {
  2.         // 验证请求参数是否正确
  3.         if (ObjectUtil.equal(requestParam.getTarget(),                   DiscountTargetEnum.PRODUCT_SPECIFIC)) {
  4.             // 验证商品是否存在,如果不存在抛出异常
  5.             // ......
  6.         }
  7.         if (StrUtil.isEmpty(requestParam.getName())) {
  8.             throw new ClientException("名称不能为空");
  9.         }
  10.         if (ObjectUtil.isEmpty(requestParam.getSource())) {
  11.             throw new ClientException("来源不能为空");
  12.         }
  13.         //...
  14.         // 新增信息到数据库
  15.         // ...
  16. }
复制代码
2.用责任链模式来修改上面的代码:
  1. public void createGoods(GoodsSaveReqDTO requestParam) {
  2.         // 通过责任链验证请求参数是否正确
  3.         ChainContext.handler(CREATE_Goods_KEY.name(), requestParam);
  4.         // 信息到数据库
  5.         // ...
  6. }
复制代码
  1. @Component
  2. public final class ChainContext<T> implements ApplicationContextAware, CommandLineRunner {
  3.     private final Map<String, List<ChainHandler>> ChainHandlerContainer = new HashMap<>();
  4.     /**
  5.      * 责任链组件执行
  6.      *
  7.      * @param mark         责任链组件标识
  8.      * @param requestParam 请求参数
  9.      */
  10.     public void handler(String mark, T requestParam) {
  11.         // 根据 mark 标识从责任链容器中获取一组责任链实现 Bean 集合
  12.         List<ChainHandler> ChainHandlers = ChainHandlerContainer.get(mark);
  13.         ChainHandlers.forEach(each -> each.handler(requestParam));
  14.     }
  15.     @Override
  16.     public void run(String... args) throws Exception {
  17.         // 从 Spring IOC 容器中获取指定接口 Spring Bean 集合
  18.         Map<String, abstractChainHandler> chainFilterMap = applicationContext.getBeansOfType(abstractChainHandler.class);
  19.         chainFilterMap.forEach((beanName, bean) -> {
  20.             // 判断 Mark 是否已经存在抽象责任链容器中,如果已经存在直接向集合新增;如果不存在,创建 Mark 和对应的集合
  21.             List<ChainHandler> ChainHandlers = ChainHandlerContainer.getOrDefault(bean.mark(), new ArrayList<>());
  22.             ChainHandlers.add(bean);
  23.             ChainHandlerContainer.put(bean.mark(), abstractChainHandlers);
  24.         });
  25.         abstractChainHandlerContainer.forEach((mark, unsortedChainHandlers) -> {
  26.             // 对每个 Mark 对应的责任链实现类集合进行排序,优先级小的在前
  27.             unsortedChainHandlers.sort(Comparator.comparing(Ordered::getOrder));
  28.         });
  29.     }
  30.     @Override
  31.     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
  32.         this.applicationContext = applicationContext;
  33.     }
  34. }
复制代码
要实现详细的handle方法就继续abstractChainHandler
  1. public interface AbstractChainHandler<T> extends Ordered {
  2.     /**
  3.      * 执行责任链逻辑
  4.      *
  5.      * @param requestParam 责任链执行入参
  6.      */
  7.     void handler(T requestParam);
  8.     /**
  9.      * @return 责任链组件标识
  10.      */
  11.     String mark();
  12. }
复制代码
  1. @Component
  2. public class GoodsCreateParamNotNullChainFilter implements AbstractChainHandler<GoodsSaveReqDTO> {
  3.     @Override
  4.     public void handler(GoodsSaveReqDTO requestParam) {
  5.         if (StrUtil.isEmpty(requestParam.getName())) {
  6.             throw new ClientException("名称不能为空");
  7.         }
  8.         if (ObjectUtil.isEmpty(requestParam.getSource())) {
  9.             throw new ClientException("来源不能为空");
  10.         }
  11.         //...其它条件        
  12.     }
  13.     @Override
  14.     public String mark() {
  15.         return CREATE_Goods_KEY.name();
  16.     }
  17.     @Override
  18.     public int getOrder() {
  19.         return 0;
  20.     }
  21. }
复制代码
如许就实现相识耦,想要添加新的判断条件,只要再写一个继续abstractChainHandler的类就可以了。
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表