专栏名称: Java基基
一个苦练基本功的 Java 公众号,所以取名 Java 基基
目录
相关文章推荐
正观新闻  ·  小米SU7 ... ·  昨天  
正观新闻  ·  小米SU7 ... ·  昨天  
一梦何求  ·  早盘韬略【0227】 ·  昨天  
一梦何求  ·  早盘韬略【0227】 ·  昨天  
爱可可-爱生活  ·  【[140星]AgentKit:AI ... ·  2 天前  
果粉之家  ·  DeepSeek预测:iPhone ... ·  2 天前  
果粉之家  ·  DeepSeek预测:iPhone ... ·  2 天前  
51好读  ›  专栏  ›  Java基基

使用Pipeline模式解耦电商保险等复杂业务

Java基基  · 公众号  ·  · 2025-01-23 11:55

正文

👉 这是一个或许对你有用 的社群

🐱 一对一交流/面试小册/简历优化/求职解惑,欢迎加入 芋道快速开发平台 知识星球。 下面是星球提供的部分资料:

👉 这是一个或许对你有用的开源项目

国产 Star 破 10w+ 的开源项目,前端包括管理后台 + 微信小程序,后端支持单体和微服务架构。

功能涵盖 RBAC 权限、SaaS 多租户、数据权限、 商城 、支付、工作流、大屏报表、微信公众号、 ERP CRM AI 大模型 等等功能:

  • Boot 仓库:https://gitee.com/zhijiantianya/ruoyi-vue-pro
  • Cloud 仓库:https://gitee.com/zhijiantianya/yudao-cloud
  • 视频教程:https://doc.iocoder.cn
【国内首批】支持 JDK 21 + SpringBoot 3.2.2、JDK 8 + Spring Boot 2.7.18 双版本

来源:juejin.cn/post/
7203993298817384508


前言

在电商,保险,餐饮领域我们经常会遇到比较复杂的业务场景,比如在电商领域的下单业务中,需要根据用户的身份(是否会员),身份等级,商品属性,用户所处的位置属性等走不同的业务分支,不同业务分支的逻辑处理可能各不相同,每个分支的逻辑处理特别多且不固定,在后续产品完善,需求迭代过程中,需要频繁对各条业务线增减或修改。这时候如果我们只是在原有业务代码的基础上堆积木,业务类可能会越来越膨胀,越来越复杂,终成shi山,以至于后期难以维护,难以及时响应业务方需求,这是一个技术人所不能忍受的。在此分享一下如何使用Pipeline模式拆分,解耦这种复杂业务。

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/ruoyi-vue-pro
  • 视频教程:https://doc.iocoder.cn/video/

Spring源码中用到的责任链

Pipeline模式是责任链模式的一个变种,首先从责任链模式说起,看过Spring源码的同学都大概看到过在核心Http请求处理类DispatcherServlet中,在获取handler的时候,具体获取到的其实是一个被包装过的HandlerExecutionChain

HandlerExecutionChain中除了handler以外,还包含一堆实现了HandlerInterceptor接口的拦截器

里面有preHandle()、postHandle()、afterCompletion()三个方法,实现这三个方法可以分别在调用"Controller"方法之前,调用"Controller"方法之后渲染"ModelAndView"之前,以及渲染"ModelAndView"之后执行,每个方法都对应着HandlerExecutionChain中的applyxxx方法,真正执行时通过 转化为数组用指针遍历执行。

此处的处理链类似于责任链。

在aop模块的ReflectiveMethodInvocation类中,执行增强逻辑时,也是通过递归调用形成责任链来执行。

public Object proceed() throws Throwable {
   // We start with an index of -1 and increment early.
   // 执行完所有增强后执行切点方法
   if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
      return invokeJoinpoint();
   }

   // 获取下一个要执行的拦截器
   Object interceptorOrInterceptionAdvice =
         this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
   if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
      // Evaluate dynamic method matcher here: static part will already have
      // been evaluated and found to match.
      // 动态匹配
      InterceptorAndDynamicMethodMatcher dm =
            (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
      Class> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
      if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
         return dm.interceptor.invoke(this);
      }
      else {
         // Dynamic matching failed.
         // Skip this interceptor and invoke the next in the chain.
         // 不匹配则不执行拦截器
         return proceed();
      }
   }
   else {
      // 普通拦截器,直接调用拦截器,比如 ExposeInvocationInterceptor,AspectJAfterAdvice
      // It's an interceptor, so we just invoke it: The pointcut will have
      // been evaluated statically before this object was constructed.
      // 传入this,形成调用链条,如MethodBeforeAdviceInterceptor,会先执行增强方法,再执行后面逻辑
      return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
   }
}

上面第一种是通过index下标去循环调用,无法终止处理,第二种通过递归,耦合比较严重,容易相互影响而无法调试,两者都不适用于业务编排。

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/yudao-cloud
  • 视频教程:https://doc.iocoder.cn/video/

Pipeline模式

上面我们说到Pipeline模式是责任链模式的一个变种,下面看看Pipeline的结构

Pipeline为链表结构,包含了头尾节点,当前上下文, 开始-结束方法,对节点的操作方法

 public class DefaultOrderPipeLine implements OrderPipeLine {
//    public static TransmittableThreadLocal pipeLineStopWatchTTL = new TransmittableThreadLocal<>();

    public OrderContext context;
    public OrderHandlerNode head;
    public OrderHandlerNode tail;

    public DefaultOrderPipeLine(OrderContext context) {
        this.context = context;
        head = new OrderHandlerNode();
        tail = head;
//      pipeLineStopWatchTTL.set(new StopWatch("DefaultCastPipeLine"));
    }
    
        @Override
    public void addFirst(OrderHandler... handlers) {
        OrderHandlerNode handlerNode;
        for (OrderHandler handler : handlers) {
            OrderHandlerNode preNode = head.getNextNode();
            handlerNode = new OrderHandlerNode(handler);
            handlerNode.setNextNode(preNode);
            head.setNextNode(handlerNode);
        }
    }

每个handler-node包含了对下一个节点的引用,部分代码如下

public class OrderHandlerNode {
    private OrderHandler handler;

    private OrderHandlerNode nextNode;

    public OrderHandlerNode(OrderHandler handler) {
        this.handler = handler;
    }
    
    public void execute(OrderContext) {
    }
   }

每个node包含了handler,各个handler之间通过统一上下文handlerContext串联通信

public class OrderContext {
    private String skuId;
    private String goodsName;
    private BigDecimal amount;
}

当触发pipeline的start方法时,handlerContext便会像一艘小船一样在水流中流动执行。上面举例我们只是创建了订单处理的pipeline,而实际真是业务场景在订单创建前可能需要作很多前置性校验,在订单创建后也可能需要作很多后续工作,如此我们可以起多条pipeline来分别处理不同业务。







请到「今天看啥」查看全文


推荐文章
一梦何求  ·  早盘韬略【0227】
昨天
一梦何求  ·  早盘韬略【0227】
昨天