溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

spring中怎么使用責(zé)任連模式

發(fā)布時間:2021-06-21 16:54:24 來源:億速云 閱讀:429 作者:Leah 欄目:大數(shù)據(jù)

spring中怎么使用責(zé)任連模式,很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來學(xué)習(xí)下,希望你能有所收獲。

1. 外部控制模式

??對于外部控制的方式,這種方式比較簡單,鏈的每個節(jié)點(diǎn)只需要專注于各自的邏輯即可,而當(dāng)前節(jié)點(diǎn)調(diào)用完成之后是否繼續(xù)調(diào)用下一個節(jié)點(diǎn),這個則由外部控制邏輯決定。這里我們以一個過濾器的實(shí)現(xiàn)邏輯進(jìn)行講解,在平常工作中,我們經(jīng)常需要根據(jù)一系列的條件對某個東西進(jìn)行過濾,比如任務(wù)服務(wù)的設(shè)計,在執(zhí)行某個任務(wù),其需要經(jīng)過諸如時效性的檢驗,風(fēng)控攔截,任務(wù)完成次數(shù)等的過濾條件的檢驗之后才能判斷當(dāng)前任務(wù)是否能夠執(zhí)行,只有在所有的過濾條件都完成之后,我們才能執(zhí)行該任務(wù)。那么,這里我們可以抽象出一個Filter接口,設(shè)計如下:

public interface Filter {

  /**
   * 用于對各個任務(wù)節(jié)點(diǎn)進(jìn)行過濾
   */
  boolean filter(Task task);

}

??這里的Filter.filter方法只有一個參數(shù)Task,主要就是控制當(dāng)天task是否需要過濾掉,其中有個boolean類型的返回值,通過該返回值告知外部控制邏輯是否需要將該task過濾掉。對于該接口的子類,我們只需要將其聲明為spring所管理的一個bean即可:

@Component
public class DurationFilter implements Filter {

  @Override
  public boolean filter(Task task) {
    System.out.println("時效性檢驗");
    return true;
  }
}
@compoment
public class Risk implements Filter {
    @override
    public boolean filter(Task task){
       System.out.println("風(fēng)控攔截");
       return true;
    }
}
@Component
public class TimesFilter implements Filter {

  @Override
  public boolean filter(Task task) {
    System.out.println("次數(shù)限制檢驗");
    return true;
  }
}

??上面我們模擬聲明了3個Filter的子類,用于設(shè)計一系列的控制當(dāng)天task是否需要被過濾的邏輯,結(jié)構(gòu)上的邏輯其實(shí)比較簡單,主要就是需要將其聲明為spring所管理的一個bean。下面是我們的控制邏輯:

@Service
public class ApplicationService {

  @Autowired
  private List<Filter> filters;

  public void mockedClient() {
    Task task = new Task(); // 這里task一般是通過數(shù)據(jù)庫查詢得到的
    for (Filter filter : filters) {
      if (!filter.filter(task)) {
        return;
      }
    }

    // 過濾完成,后續(xù)是執(zhí)行任務(wù)的邏輯
  }
}

??上述的控制邏輯中,對于過濾器的獲取,只需要通過spring的自動注入即可,這里的注入是一個List<Filter>,就是說,如果我們有新的Filter實(shí)例需要參與責(zé)任鏈的過濾,只需要聲明為一個Spring容器所管理的bean即可。
??這種責(zé)任鏈設(shè)計方式的優(yōu)點(diǎn)在于鏈的控制簡單,只需要實(shí)現(xiàn)一個統(tǒng)一的接口即可,基本上滿足大部分的邏輯控制,但是對于某些動態(tài)調(diào)整鏈的需求就無能為力了。比如在執(zhí)行到某個節(jié)點(diǎn)之后需要動態(tài)的判斷師傅執(zhí)行下一個節(jié)點(diǎn),或者說要執(zhí)行,某些分叉點(diǎn)的節(jié)點(diǎn)等。這個時候,我們就需要將鏈節(jié)點(diǎn)的傳遞工作交個各個節(jié)點(diǎn)執(zhí)行。

1. 外部控制模式
對于節(jié)點(diǎn)控制調(diào)用的方式,其主要有三個控制點(diǎn):Handler,HandlerContext和PipeLine。Handle是用于編寫具體的業(yè)務(wù)代碼,HandlerContext用于對Handler進(jìn)行包裹,并且用于控制下一個節(jié)點(diǎn)的調(diào)用;PipeLine則主要是用于控制整體的流程調(diào)用的,比如對于任務(wù)的執(zhí)行,其有任務(wù)查詢,任務(wù)的過濾和執(zhí)行任務(wù)等等流程,這些流程整體的邏輯控制就是有pipeline控制,在每個流程中又包含了一些列的子流程,這些子流程則是由一個個的HandlerContext和Handler進(jìn)行梳理的,這種責(zé)任鏈的控制方式整體邏輯如下圖所示:

spring中怎么使用責(zé)任連模式![]
從上圖可以看出,我們整個流程通過pipeline對象進(jìn)行了抽象,這里主要分為了3個步驟:查詢task,過濾task和執(zhí)行task。在每個步驟中,我們都是用一系列的鏈?zhǔn)秸{(diào)用。途中需要注意的是,在每次調(diào)用鏈的下一個節(jié)點(diǎn)的時候,我們都是通過具體的Handler進(jìn)行的,也就是說進(jìn)行鏈的下一個節(jié)點(diǎn)的調(diào)用,我們是通過業(yè)務(wù)實(shí)現(xiàn)方來進(jìn)行動態(tài)的控制。

關(guān)于該模式的設(shè)計,我們首先需要強(qiáng)調(diào)的就是Handler接口的設(shè)計,其設(shè)計如下所示:

public interface Handler {

  /**
   * 處理接收到前端請求的邏輯
   */
  default void receiveTask(HandlerContext ctx, Request request) {
    ctx.fireTaskReceived(request);
  }

  /**
   * 查詢到task之后,進(jìn)行task過濾的邏輯
   */
  default void filterTask(HandlerContext ctx, Task task) {
    ctx.fireTaskFiltered(task);
  }

  /**
   * task過濾完成之后,處理執(zhí)行task的邏輯
   */
  default void executeTask(HandlerContext ctx, Task task) {
    ctx.fireTaskExecuted(task);
  }

  /**
   * 當(dāng)實(shí)現(xiàn)的前面的方法拋出異常時,將使用當(dāng)前方法進(jìn)行異常處理,這樣可以將每個handler的異常
   * 都只在該handler內(nèi)進(jìn)行處理,而無需額外進(jìn)行捕獲
   */
  default void exceptionCaught(HandlerContext ctx, Throwable e) {
    throw new RuntimeException(e);
  }

  /**
   * 在整個流程中,保證最后一定會執(zhí)行的代碼,主要是用于一些清理工作
   */
  default void afterCompletion(HandlerContext ctx) {
    ctx.fireAfterCompletion(ctx);
  }
}

這里的Handler接口主要是對具體的業(yè)務(wù)邏輯的一個抽象,對于該Handler主要有如下幾點(diǎn)需要說明:

  • 在前面圖中pipline的每個層級中對應(yīng)于改Handler都有一個方法,在需要進(jìn)行具體的業(yè)務(wù)處理的時候,用戶只需要聲明一個bean,具體實(shí)現(xiàn)某個業(yè)務(wù)所需要處理的層級的方法即可,無需管其他的邏輯;

  • 每個層級的方法都有默認(rèn)的實(shí)現(xiàn),默認(rèn)實(shí)現(xiàn)方式就是將鏈的調(diào)用繼續(xù)往下進(jìn)行傳遞

  • 每個層級的方法中,第一個參數(shù)都是一個Handler類型的,該參數(shù)主要是用于進(jìn)行流程控制的,比如是否需要將當(dāng)前層級的調(diào)用鏈繼續(xù)往下傳遞,這里的鏈的傳遞工作主要是通過ctx.filterXXX()方法進(jìn)行

  • 每個Handler中都有一個exceptionCaught()和afterCompletion()方法,這兩個方法分別用于異常的控制和所有調(diào)用完成之后的清理,這里的異常控制主要是捕獲當(dāng)前Handler中的異常,而afterCompetition()方法則會保證所有步驟之后一定會進(jìn)行調(diào)用的,五路是否拋出異常;

  • 對于Handler的使用,我們希望能夠達(dá)到的目的是,使用方只需要實(shí)現(xiàn)該接口,并且使用某個注解來將其標(biāo)志位spring bean即可,無需管整個pipeline的組裝和流程控制。通過這種方式,我們既保留了每個spring提供給我們的便利性,也使用了pipeline模式的靈活性
    上述流程代碼中,我們注意到,每個層級的方法中都有一個HandlerContext用于傳遞鏈的相關(guān)控制信息,我們來看下關(guān)于這部分的源碼:

@Component
@Scope("prototype")
public class HandlerContext {

  HandlerContext prev;
  HandlerContext next;
  Handler handler;

  private Task task;

  public void fireTaskReceived(Request request) {
    invokeTaskReceived(next(), request);
  }

  /**
   * 處理接收到任務(wù)的事件
   */
  static void invokeTaskReceived(HandlerContext ctx, Request request) {
    if (ctx != null) {
      try {
        ctx.handler().receiveTask(ctx, request);
      } catch (Throwable e) {
        ctx.handler().exceptionCaught(ctx, e);
      }
    }
  }

  public void fireTaskFiltered(Task task) {
    invokeTaskFiltered(next(), task);
  }

  /**
   * 處理任務(wù)過濾事件
   */
  static void invokeTaskFiltered(HandlerContext ctx, Task task) {
    if (null != ctx) {
      try {
        ctx.handler().filterTask(ctx, task);
      } catch (Throwable e) {
        ctx.handler().exceptionCaught(ctx, e);
      }
    }
  }

  public void fireTaskExecuted(Task task) {
    invokeTaskExecuted(next(), task);
  }

  /**
   * 處理執(zhí)行任務(wù)事件
   */
  static void invokeTaskExecuted(HandlerContext ctx, Task task) {
    if (null != ctx) {
      try {
        ctx.handler().executeTask(ctx, task);
      } catch (Exception e) {
        ctx.handler().exceptionCaught(ctx, e);
      }
    }
  }

  public void fireAfterCompletion(HandlerContext ctx) {
    invokeAfterCompletion(next());
  }

  static void invokeAfterCompletion(HandlerContext ctx) {
    if (null != ctx) {
      ctx.handler().afterCompletion(ctx);
    }
  }

  private HandlerContext next() {
    return next;
  }

  private Handler handler() {
    return handler;
  }
}

在HandlerContext中,我們需要說明幾點(diǎn):

  • 之前Handler接口默認(rèn)實(shí)現(xiàn)的ctx.filterXXX()方法,這里都委托給了對應(yīng)的invokeXXX方法進(jìn)行調(diào)用,而且我們注意到,在傳遞invokeXXX()方法的參數(shù)里,傳入的HandlerContext對象都是通過next()方法獲取到的。也就是說我們在Handler中調(diào)用ctx.filterXXX方法時,都是在調(diào)用當(dāng)前Handler的下一個Handler對應(yīng)的層級方法,通過這種方式我們就可以實(shí)現(xiàn)鏈?zhǔn)降膫鬟f調(diào)用;

  • 在上一點(diǎn)中我們說到,在某個Handler中如果想讓鏈往下傳遞,只需要調(diào)用FilterXXX()方法即可,如果我們在某個Handler中,根據(jù)業(yè)務(wù),當(dāng)前層級已經(jīng)調(diào)用完成,而無需調(diào)用后續(xù)的Handler,那么我們就不需要調(diào)用ctx.filterXXX()方法即可;

  • 在HandlerContext中,我們也實(shí)現(xiàn)了invokeXXX()方法,該方法的作用是提供給外部的pipeline調(diào)用的,開啟每個層級的鏈;

  • 在每個invokeXXX()方法中,我們都是用try...catch將當(dāng)前層級的調(diào)用拋出異常捕獲了,然后調(diào)用ctx.handler().exceptionCaught()方法即可,異常捕獲流程就是在這里的HandlerContext()中處理的;

  • 在HandlerContext的聲明處,我們需要注意到,其使用了@conpoment和@("prototype")注解進(jìn)行標(biāo)注了,這說明我們的HandlerContext是有spring 容器管理的,并且由于我們每個Handler實(shí)際都由HandlerContext維護(hù),所以這里必須聲明為prototype類型。通過這種方式,我們的HandlerContext也就具備著諸如spring相關(guān)的bean的功能,能夠根據(jù)業(yè)務(wù)需求進(jìn)行一些額外的處理;
    前面我們講解了Handler和HandlerContext的具體實(shí)現(xiàn),以及實(shí)現(xiàn)的過程需要注意的一些問題,下面我們將來看進(jìn)行流程控制的pipeline是如何實(shí)現(xiàn)的,如下是其接口的定義:

public interface Pipeline {
  
  Pipeline fireTaskReceived();
  
  Pipeline fireTaskFiltered();
  
  Pipeline fireTaskExecuted();
  
  Pipeline fireAfterCompletion();
}

這里主要是定義了一個pipeline接口,該接口定義了一些列的層級調(diào)用,是每個層級的入口方法,如下是該接口的實(shí)現(xiàn)類:

@Component("pipeline")
@Scope("prototype")
public class DefaultPipeline implements Pipeline, ApplicationContextAware, InitializingBean {
  // 創(chuàng)建一個默認(rèn)的handler,將其注入到首尾兩個節(jié)點(diǎn)的HandlerContext中,其作用只是將鏈往下傳遞
  private static final Handler DEFAULT_HANDLER = new Handler() {};

  // 將ApplicationContext注入進(jìn)來的主要原因在于,HandlerContext是prototype類型的,因而需要
  // 通過ApplicationContext.getBean()方法來獲取其實(shí)例
  private ApplicationContext context;

  // 創(chuàng)建一個頭結(jié)點(diǎn)和尾節(jié)點(diǎn),這兩個節(jié)點(diǎn)內(nèi)部沒有做任何處理,只是默認(rèn)的將每一層級的鏈往下傳遞,
  // 這里頭結(jié)點(diǎn)和尾節(jié)點(diǎn)的主要作用就是用于標(biāo)志整個鏈的首尾,所有的業(yè)務(wù)節(jié)點(diǎn)都在這兩個節(jié)點(diǎn)中間
  private HandlerContext head;
  private HandlerContext tail;

  // 用于業(yè)務(wù)調(diào)用的request對象,其內(nèi)部封裝了業(yè)務(wù)數(shù)據(jù)
  private Request request;
  // 用于執(zhí)行任務(wù)的task對象
  private Task task;

  // 最初始的業(yè)務(wù)數(shù)據(jù)需要通過構(gòu)造函數(shù)傳入,因為這是驅(qū)動整個pipeline所需要的數(shù)據(jù),
  // 一般通過外部調(diào)用方的參數(shù)進(jìn)行封裝即可
  public DefaultPipeline(Request request) {
    this.request = request;
  }

  // 這里我們可以看到,每一層級的調(diào)用都是通過HandlerContext.invokeXXX(head)的方式進(jìn)行的,
  // 也就是說我們每一層級鏈的入口都是從頭結(jié)點(diǎn)開始的,當(dāng)然在某些情況下,我們也需要從尾節(jié)點(diǎn)開始鏈
  // 的調(diào)用,這個時候傳入tail即可。
  @Override
  public Pipeline fireTaskReceived() {
    HandlerContext.invokeTaskReceived(head, request);
    return this;
  }

  // 觸發(fā)任務(wù)過濾的鏈調(diào)用
  @Override
  public Pipeline fireTaskFiltered() {
    HandlerContext.invokeTaskFiltered(head, task);
    return this;
  }

  // 觸發(fā)任務(wù)執(zhí)行的鏈執(zhí)行
  @Override
  public Pipeline fireTaskExecuted() {
    HandlerContext.invokeTaskExecuted(head, task);
    return this;
  }

  // 觸發(fā)最終完成的鏈的執(zhí)行
  @Override
  public Pipeline fireAfterCompletion() {
    HandlerContext.invokeAfterCompletion(head);
    return this;
  }
  
  // 用于往Pipeline中添加節(jié)點(diǎn)的方法,讀者朋友也可以實(shí)現(xiàn)其他的方法用于進(jìn)行鏈的維護(hù)
  void addLast(Handler handler) {
    HandlerContext handlerContext = newContext(handler);
    tail.prev.next = handlerContext;
    handlerContext.prev = tail.prev;
    handlerContext.next = tail;
    tail.prev = handlerContext;
  }

  // 這里通過實(shí)現(xiàn)InitializingBean接口來達(dá)到初始化Pipeline的目的,可以看到,這里初始的時候
  // 我們通過ApplicationContext實(shí)例化了兩個HandlerContext對象,然后將head.next指向tail節(jié)點(diǎn),
  // 將tail.prev指向head節(jié)點(diǎn)。也就是說,初始時,整個鏈只有頭結(jié)點(diǎn)和尾節(jié)點(diǎn)。
  @Override
  public void afterPropertiesSet() throws Exception {
    head = newContext(DEFAULT_HANDLER);
    tail = newContext(DEFAULT_HANDLER);
    head.next = tail;
    tail.prev = head;
  }

  // 使用默認(rèn)的Handler初始化一個HandlerContext
  private HandlerContext newContext(Handler handler) {
    HandlerContext context = this.context.getBean(HandlerContext.class);
    context.handler = handler;
    return context;
  }

  // 注入ApplicationContext對象
  @Override
  public void setApplicationContext(ApplicationContext applicationContext) {
    this.context = applicationContext;
  }
}

關(guān)于defaultPipeline的實(shí)現(xiàn),有以下幾點(diǎn)需要說明:

  • defaultpipeline 使用@compoment和@scope("prototype")注解進(jìn)行了標(biāo)注,當(dāng)前一個注解用于將其聲明為一個spring容器所管理的bean,而后一個注解則用于表征defaultPipeline是個多例類型,很明顯的,這里的pipeLine是有狀態(tài)的。這里需要進(jìn)行說明的是,'有狀態(tài)'主要是因為我們可能會根據(jù)業(yè)務(wù)情況的動態(tài)的調(diào)整整個鏈的節(jié)點(diǎn)情況,而且這里的request和task對象都是與具體的業(yè)務(wù)相關(guān)的,因為必須聲明為prototype類型;

  • 上面的示例中,request對象是通過構(gòu)造pipeline對象的時候傳進(jìn)來的,而task對象則是在pipeline的流轉(zhuǎn)過程中生成的,這里比如通過完成filterTaskReceived()鏈的調(diào)用之后,就需要通過外部請求request得到一個task對象,從而進(jìn)行后續(xù)的處理;

  • 對于后續(xù)寫業(yè)務(wù)代碼的人而言,其只需要實(shí)現(xiàn)一個Handler接口即可,無需要處理鏈相關(guān)的所有邏輯,以為我們需要獲取到所有實(shí)現(xiàn)Handler接口的bean;

  • 將實(shí)現(xiàn)了Handler接口的bean通過Handlercontext進(jìn)行封裝,然后將其添加到pipeline中
    這里的第一個問題好處理,因為通過ApplicationContext就可以獲取實(shí)現(xiàn)了某個接口的所有bean,而第二個問題我們可以通過聲明了BeanPostProcessoor接口的類來實(shí)現(xiàn)。如下是具體的實(shí)現(xiàn)代碼:

verride
  public void setApplicationContext(ApplicationContext applicationContext) {
    this.context = applicationContext;
  }
}
       關(guān)于DefaultPipeline的實(shí)現(xiàn),主要有如下幾點(diǎn)需要說明:

DefaultPipeline使用@Component和@Scope("prototype")注解進(jìn)行了標(biāo)注,前一個注解用于將其聲明為一個Spring容器所管理的bean,而后一個注解則用于表征DefaultPipeline是一個多例類型的,很明顯,這里的Pipeline是有狀態(tài)的。這里需要進(jìn)行說明的是,"有狀態(tài)"主要是因為我們可能會根據(jù)業(yè)務(wù)情況動態(tài)的調(diào)整個鏈的節(jié)點(diǎn)情況,而且這里的Request和Task對象都是與具體的業(yè)務(wù)相關(guān)的,因而必須聲明為prototype類型;
上面的示例中,Request對象是通過構(gòu)造Pipeline對象的時候傳進(jìn)來的,而Task對象則是在Pipeline的流轉(zhuǎn)過程中生成的,這里比如通過完成fireTaskReceived()鏈的調(diào)用之后,就需要通過外部請求Request得到一個Task對象,從而進(jìn)行整個Pipeline的后續(xù)處理;
       這里我們已經(jīng)實(shí)現(xiàn)了Pipeline,HandlerContext和Handler,知道這些bean都是被Spring所管理的bean,那么我們接下來的問題主要在于如何進(jìn)行整個鏈的組裝。這里的組裝方式比較簡單,其主要需要解決兩個問題:

對于后續(xù)寫業(yè)務(wù)代碼的人而言,其只需要實(shí)現(xiàn)一個Handler接口即可,而無需處理與鏈相關(guān)的所有邏輯,因而我們需要獲取到所有實(shí)現(xiàn)了Handler接口的bean;
將實(shí)現(xiàn)了Handler接口的bean通過HandlerContext進(jìn)行封裝,然后將其添加到Pipeline中。
       這里的第一個問題比較好處理,因為通過ApplicationContext就可以獲取實(shí)現(xiàn)了某個接口的所有bean,而第二個問題我們可以通過聲明一個實(shí)現(xiàn)了BeanPostProcessor接口的類來實(shí)現(xiàn)。如下是其實(shí)現(xiàn)代碼:

@Component
public class HandlerBeanProcessor implements BeanPostProcessor, ApplicationContextAware {

  private ApplicationContext context;

  // 該方法會在一個bean初始化完成后調(diào)用,這里主要是在Pipeline初始化完成之后獲取所有實(shí)現(xiàn)了
  // Handler接口的bean,然后通過調(diào)用Pipeline.addLast()方法將其添加到pipeline中
  @Override
  public Object postProcessAfterInitialization(Object bean, String beanName) {
    if (bean instanceof DefaultPipeline) {
      DefaultPipeline pipeline = (DefaultPipeline) bean;
      Map<String, Handler> handlerMap = context.getBeansOfType(Handler.class);
      handlerMap.forEach((name, handler) -> pipeline.addLast(handler));
    }

    return bean;
  }

  @Override
  public void setApplicationContext(ApplicationContext applicationContext) {
    this.context = applicationContext;
  }
}

這里我們整個鏈路的維護(hù)工作就完成,可以看到,現(xiàn)在基本已經(jīng)實(shí)現(xiàn)了鏈?zhǔn)搅鞒炭刂啤_@里需要說明的一點(diǎn)是,上面的HandlerBeanProcessor.postProcessAfterInitialization()方法的執(zhí)行是在InitializingBean.afterPropertySet()方法之后執(zhí)行的,也就是說這里的HandlerBeanProcessor在執(zhí)行的時候,整個pipeline就是已經(jīng)完成初始化的了。下面我們來看下外部客戶端如何進(jìn)行這個鏈路流程的控制:

HandlerBeanProcessor在執(zhí)行時,整個Pipeline是已經(jīng)初始化完成了的。下面我們來看一下外部客戶端如何進(jìn)行整個鏈?zhǔn)橇鞒痰目刂疲?

@Service
public class ApplicationService {

  @Autowired
  private ApplicationContext context;
  
  public void mockedClient() {
    Request request = new Request();  // request一般是通過外部調(diào)用獲取
    Pipeline pipeline = newPipeline(request);
    try {
      pipeline.fireTaskReceived();
      pipeline.fireTaskFiltered();
      pipeline.fireTaskExecuted();
    } finally {
      pipeline.fireAfterCompletion();
    }
  }
  
  private Pipeline newPipeline(Request request) {
    return context.getBean(DefaultPipeline.class, request);
  }
}

這里我們模擬一個客戶端的調(diào)用,首先創(chuàng)建了一個pipeline對象,然后依次調(diào)用各個層級的方法,并且這里我們使用try....finally結(jié)構(gòu)來保證Pipeline.fireAfterCompletion()方法一定會執(zhí)行。如此我們就完成了整個責(zé)任鏈路模式的構(gòu)造。這里我們使用前面用到的時效性的filter來作為示例來實(shí)現(xiàn)一個Handler:

@Component
public class DurationHandler implements Handler {

  @Override
  public void filterTask(HandlerContext ctx, Task task) {
    System.out.println("時效性檢驗");
    ctx.fireTaskFiltered(task);
  }
}

關(guān)于這里具體的業(yè)務(wù)我們需要說明的有如下幾點(diǎn):

  • 改Handler必須使用@compoment注解來將其聲明為spring容器管理的bean,這樣我們前面實(shí)現(xiàn)的HandlerBeanProcessor 才能動態(tài)的添加到整個pipeline中;

  • 在每個Handler中,需要根據(jù)當(dāng)前的業(yè)務(wù)需要來實(shí)現(xiàn)具體的層級方法,比如這里是進(jìn)行時效性檢驗的,就是"任務(wù)過濾"這一層級的邏輯,因為時效性檢驗通過我們才能執(zhí)行這個task,因而這里需要實(shí)現(xiàn)的是Handler.filterTask()方法,如果我們需要實(shí)現(xiàn)的是執(zhí)行task的邏輯,那么需要實(shí)現(xiàn)的是Handler.executeTask()方法; 在實(shí)現(xiàn)完具體的業(yè)務(wù)邏輯之后,我們可以根據(jù)當(dāng)前的業(yè)務(wù)需要看是否需要將當(dāng)前層級的鏈繼續(xù)往下傳遞,也就是這里的ctx.fireTaskFiltered(task);方法的調(diào)用,我們可以看前面HandlerContext.fireXXX()方法就是會獲取當(dāng)前節(jié)點(diǎn)的下一個節(jié)點(diǎn),然后進(jìn)行調(diào)用。如果根據(jù)業(yè)務(wù)需要,不需要將鏈往下傳遞,那么就不需要調(diào)用ctx.fireTaskFiltered(task);

看完上述內(nèi)容是否對您有幫助呢?如果還想對相關(guān)知識有進(jìn)一步的了解或閱讀更多相關(guān)文章,請關(guān)注億速云行業(yè)資訊頻道,感謝您對億速云的支持。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI