spring中怎么使用責(zé)任連模式,很多新手對(duì)此不是很清楚,為了幫助大家解決這個(gè)難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來(lái)學(xué)習(xí)下,希望你能有所收獲。
讓客戶滿意是我們工作的目標(biāo),不斷超越客戶的期望值來(lái)自于我們對(duì)這個(gè)行業(yè)的熱愛(ài)。我們立志把好的技術(shù)通過(guò)有效、簡(jiǎn)單的方式提供給客戶,將通過(guò)不懈努力成為客戶在信息化領(lǐng)域值得信任、有價(jià)值的長(zhǎng)期合作伙伴,公司提供的服務(wù)項(xiàng)目有:國(guó)際域名空間、虛擬主機(jī)、營(yíng)銷軟件、網(wǎng)站建設(shè)、衢江網(wǎng)站維護(hù)、網(wǎng)站推廣。
1. 外部控制模式
??對(duì)于外部控制的方式,這種方式比較簡(jiǎn)單,鏈的每個(gè)節(jié)點(diǎn)只需要專注于各自的邏輯即可,而當(dāng)前節(jié)點(diǎn)調(diào)用完成之后是否繼續(xù)調(diào)用下一個(gè)節(jié)點(diǎn),這個(gè)則由外部控制邏輯決定。這里我們以一個(gè)過(guò)濾器的實(shí)現(xiàn)邏輯進(jìn)行講解,在平常工作中,我們經(jīng)常需要根據(jù)一系列的條件對(duì)某個(gè)東西進(jìn)行過(guò)濾,比如任務(wù)服務(wù)的設(shè)計(jì),在執(zhí)行某個(gè)任務(wù),其需要經(jīng)過(guò)諸如時(shí)效性的檢驗(yàn),風(fēng)控?cái)r截,任務(wù)完成次數(shù)等的過(guò)濾條件的檢驗(yàn)之后才能判斷當(dāng)前任務(wù)是否能夠執(zhí)行,只有在所有的過(guò)濾條件都完成之后,我們才能執(zhí)行該任務(wù)。那么,這里我們可以抽象出一個(gè)Filter接口,設(shè)計(jì)如下:
public interface Filter { /** * 用于對(duì)各個(gè)任務(wù)節(jié)點(diǎn)進(jìn)行過(guò)濾 */ boolean filter(Task task); }
??這里的Filter.filter方法只有一個(gè)參數(shù)Task,主要就是控制當(dāng)天task是否需要過(guò)濾掉,其中有個(gè)boolean類型的返回值,通過(guò)該返回值告知外部控制邏輯是否需要將該task過(guò)濾掉。對(duì)于該接口的子類,我們只需要將其聲明為spring所管理的一個(gè)bean即可:
@Component public class DurationFilter implements Filter { @Override public boolean filter(Task task) { System.out.println("時(shí)效性檢驗(yàn)"); return true; } }
@compoment public class Risk implements Filter { @override public boolean filter(Task task){ System.out.println("風(fēng)控?cái)r截"); return true; } }
@Component public class TimesFilter implements Filter { @Override public boolean filter(Task task) { System.out.println("次數(shù)限制檢驗(yàn)"); return true; } }
??上面我們模擬聲明了3個(gè)Filter的子類,用于設(shè)計(jì)一系列的控制當(dāng)天task是否需要被過(guò)濾的邏輯,結(jié)構(gòu)上的邏輯其實(shí)比較簡(jiǎn)單,主要就是需要將其聲明為spring所管理的一個(gè)bean。下面是我們的控制邏輯:
@Service public class ApplicationService { @Autowired private List<Filter> filters; public void mockedClient() { Task task = new Task(); // 這里task一般是通過(guò)數(shù)據(jù)庫(kù)查詢得到的 for (Filter filter : filters) { if (!filter.filter(task)) { return; } } // 過(guò)濾完成,后續(xù)是執(zhí)行任務(wù)的邏輯 } }
??上述的控制邏輯中,對(duì)于過(guò)濾器的獲取,只需要通過(guò)spring的自動(dòng)注入即可,這里的注入是一個(gè)List<Filter>,就是說(shuō),如果我們有新的Filter實(shí)例需要參與責(zé)任鏈的過(guò)濾,只需要聲明為一個(gè)Spring容器所管理的bean即可。
??這種責(zé)任鏈設(shè)計(jì)方式的優(yōu)點(diǎn)在于鏈的控制簡(jiǎn)單,只需要實(shí)現(xiàn)一個(gè)統(tǒng)一的接口即可,基本上滿足大部分的邏輯控制,但是對(duì)于某些動(dòng)態(tài)調(diào)整鏈的需求就無(wú)能為力了。比如在執(zhí)行到某個(gè)節(jié)點(diǎn)之后需要?jiǎng)討B(tài)的判斷師傅執(zhí)行下一個(gè)節(jié)點(diǎn),或者說(shuō)要執(zhí)行,某些分叉點(diǎn)的節(jié)點(diǎn)等。這個(gè)時(shí)候,我們就需要將鏈節(jié)點(diǎn)的傳遞工作交個(gè)各個(gè)節(jié)點(diǎn)執(zhí)行。
1. 外部控制模式
對(duì)于節(jié)點(diǎn)控制調(diào)用的方式,其主要有三個(gè)控制點(diǎn):Handler,HandlerContext和PipeLine。Handle是用于編寫(xiě)具體的業(yè)務(wù)代碼,HandlerContext用于對(duì)Handler進(jìn)行包裹,并且用于控制下一個(gè)節(jié)點(diǎn)的調(diào)用;PipeLine則主要是用于控制整體的流程調(diào)用的,比如對(duì)于任務(wù)的執(zhí)行,其有任務(wù)查詢,任務(wù)的過(guò)濾和執(zhí)行任務(wù)等等流程,這些流程整體的邏輯控制就是有pipeline控制,在每個(gè)流程中又包含了一些列的子流程,這些子流程則是由一個(gè)個(gè)的HandlerContext和Handler進(jìn)行梳理的,這種責(zé)任鏈的控制方式整體邏輯如下圖所示:
![]
從上圖可以看出,我們整個(gè)流程通過(guò)pipeline對(duì)象進(jìn)行了抽象,這里主要分為了3個(gè)步驟:查詢task,過(guò)濾task和執(zhí)行task。在每個(gè)步驟中,我們都是用一系列的鏈?zhǔn)秸{(diào)用。途中需要注意的是,在每次調(diào)用鏈的下一個(gè)節(jié)點(diǎn)的時(shí)候,我們都是通過(guò)具體的Handler進(jìn)行的,也就是說(shuō)進(jìn)行鏈的下一個(gè)節(jié)點(diǎn)的調(diào)用,我們是通過(guò)業(yè)務(wù)實(shí)現(xiàn)方來(lái)進(jìn)行動(dòng)態(tài)的控制。
關(guān)于該模式的設(shè)計(jì),我們首先需要強(qiáng)調(diào)的就是Handler接口的設(shè)計(jì),其設(shè)計(jì)如下所示:
public interface Handler { /** * 處理接收到前端請(qǐng)求的邏輯 */ default void receiveTask(HandlerContext ctx, Request request) { ctx.fireTaskReceived(request); } /** * 查詢到task之后,進(jìn)行task過(guò)濾的邏輯 */ default void filterTask(HandlerContext ctx, Task task) { ctx.fireTaskFiltered(task); } /** * task過(guò)濾完成之后,處理執(zhí)行task的邏輯 */ default void executeTask(HandlerContext ctx, Task task) { ctx.fireTaskExecuted(task); } /** * 當(dāng)實(shí)現(xiàn)的前面的方法拋出異常時(shí),將使用當(dāng)前方法進(jìn)行異常處理,這樣可以將每個(gè)handler的異常 * 都只在該handler內(nèi)進(jìn)行處理,而無(wú)需額外進(jìn)行捕獲 */ default void exceptionCaught(HandlerContext ctx, Throwable e) { throw new RuntimeException(e); } /** * 在整個(gè)流程中,保證最后一定會(huì)執(zhí)行的代碼,主要是用于一些清理工作 */ default void afterCompletion(HandlerContext ctx) { ctx.fireAfterCompletion(ctx); } }
這里的Handler
接口主要是對(duì)具體的業(yè)務(wù)邏輯的一個(gè)抽象,對(duì)于該Handler主要有如下幾點(diǎn)需要說(shuō)明:
在前面圖中pipline
的每個(gè)層級(jí)中對(duì)應(yīng)于改Handler都有一個(gè)方法,在需要進(jìn)行具體的業(yè)務(wù)處理的時(shí)候,用戶只需要聲明一個(gè)bean,具體實(shí)現(xiàn)某個(gè)業(yè)務(wù)所需要處理的層級(jí)的方法即可,無(wú)需管其他的邏輯;
每個(gè)層級(jí)的方法都有默認(rèn)的實(shí)現(xiàn),默認(rèn)實(shí)現(xiàn)方式就是將鏈的調(diào)用繼續(xù)往下進(jìn)行傳遞
每個(gè)層級(jí)的方法中,第一個(gè)參數(shù)都是一個(gè)Handler
類型的,該參數(shù)主要是用于進(jìn)行流程控制的,比如是否需要將當(dāng)前層級(jí)的調(diào)用鏈繼續(xù)往下傳遞,這里的鏈的傳遞工作主要是通過(guò)ctx.filterXXX()
方法進(jìn)行
每個(gè)Handler中都有一個(gè)exceptionCaught()和afterCompletion()方法,這兩個(gè)方法分別用于異常的控制和所有調(diào)用完成之后的清理,這里的異??刂浦饕遣东@當(dāng)前Handler中的異常,而afterCompetition()方法則會(huì)保證所有步驟之后一定會(huì)進(jìn)行調(diào)用的,五路是否拋出異常;
對(duì)于Handler的使用,我們希望能夠達(dá)到的目的是,使用方只需要實(shí)現(xiàn)該接口,并且使用某個(gè)注解來(lái)將其標(biāo)志位spring bean即可,無(wú)需管整個(gè)pipeline的組裝和流程控制。通過(guò)這種方式,我們既保留了每個(gè)spring提供給我們的便利性,也使用了pipeline模式的靈活性
上述流程代碼中,我們注意到,每個(gè)層級(jí)的方法中都有一個(gè)HandlerContext用于傳遞鏈的相關(guān)控制信息,我們來(lái)看下關(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ù)過(guò)濾事件 */ 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中,我們需要說(shuō)明幾點(diǎn):
之前Handler接口默認(rèn)實(shí)現(xiàn)的ctx.filterXXX()方法,這里都委托給了對(duì)應(yīng)的invokeXXX方法進(jìn)行調(diào)用,而且我們注意到,在傳遞invokeXXX()方法的參數(shù)里,傳入的HandlerContext對(duì)象都是通過(guò)next()方法獲取到的。也就是說(shuō)我們?cè)贖andler中調(diào)用ctx.filterXXX方法時(shí),都是在調(diào)用當(dāng)前Handler的下一個(gè)Handler對(duì)應(yīng)的層級(jí)方法,通過(guò)這種方式我們就可以實(shí)現(xiàn)鏈?zhǔn)降膫鬟f調(diào)用;
在上一點(diǎn)中我們說(shuō)到,在某個(gè)Handler中如果想讓鏈往下傳遞,只需要調(diào)用FilterXXX()方法即可,如果我們?cè)谀硞€(gè)Handler中,根據(jù)業(yè)務(wù),當(dāng)前層級(jí)已經(jīng)調(diào)用完成,而無(wú)需調(diào)用后續(xù)的Handler,那么我們就不需要調(diào)用ctx.filterXXX()方法即可;
在HandlerContext中,我們也實(shí)現(xiàn)了invokeXXX()方法,該方法的作用是提供給外部的pipeline調(diào)用的,開(kāi)啟每個(gè)層級(jí)的鏈;
在每個(gè)invokeXXX()方法中,我們都是用try...catch將當(dāng)前層級(jí)的調(diào)用拋出異常捕獲了,然后調(diào)用ctx.handler().exceptionCaught()方法即可,異常捕獲流程就是在這里的HandlerContext()中處理的;
在HandlerContext的聲明處,我們需要注意到,其使用了@conpoment和@("prototype")注解進(jìn)行標(biāo)注了,這說(shuō)明我們的HandlerContext是有spring 容器管理的,并且由于我們每個(gè)Handler實(shí)際都由HandlerContext維護(hù),所以這里必須聲明為prototype類型。通過(guò)這種方式,我們的HandlerContext也就具備著諸如spring相關(guān)的bean的功能,能夠根據(jù)業(yè)務(wù)需求進(jìn)行一些額外的處理;
前面我們講解了Handler和HandlerContext的具體實(shí)現(xiàn),以及實(shí)現(xiàn)的過(guò)程需要注意的一些問(wèn)題,下面我們將來(lái)看進(jìn)行流程控制的pipeline是如何實(shí)現(xiàn)的,如下是其接口的定義:
public interface Pipeline { Pipeline fireTaskReceived(); Pipeline fireTaskFiltered(); Pipeline fireTaskExecuted(); Pipeline fireAfterCompletion(); }
這里主要是定義了一個(gè)pipeline接口,該接口定義了一些列的層級(jí)調(diào)用,是每個(gè)層級(jí)的入口方法,如下是該接口的實(shí)現(xiàn)類:
@Component("pipeline") @Scope("prototype") public class DefaultPipeline implements Pipeline, ApplicationContextAware, InitializingBean { // 創(chuàng)建一個(gè)默認(rèn)的handler,將其注入到首尾兩個(gè)節(jié)點(diǎn)的HandlerContext中,其作用只是將鏈往下傳遞 private static final Handler DEFAULT_HANDLER = new Handler() {}; // 將ApplicationContext注入進(jìn)來(lái)的主要原因在于,HandlerContext是prototype類型的,因而需要 // 通過(guò)ApplicationContext.getBean()方法來(lái)獲取其實(shí)例 private ApplicationContext context; // 創(chuàng)建一個(gè)頭結(jié)點(diǎn)和尾節(jié)點(diǎn),這兩個(gè)節(jié)點(diǎn)內(nèi)部沒(méi)有做任何處理,只是默認(rèn)的將每一層級(jí)的鏈往下傳遞, // 這里頭結(jié)點(diǎn)和尾節(jié)點(diǎn)的主要作用就是用于標(biāo)志整個(gè)鏈的首尾,所有的業(yè)務(wù)節(jié)點(diǎn)都在這兩個(gè)節(jié)點(diǎn)中間 private HandlerContext head; private HandlerContext tail; // 用于業(yè)務(wù)調(diào)用的request對(duì)象,其內(nèi)部封裝了業(yè)務(wù)數(shù)據(jù) private Request request; // 用于執(zhí)行任務(wù)的task對(duì)象 private Task task; // 最初始的業(yè)務(wù)數(shù)據(jù)需要通過(guò)構(gòu)造函數(shù)傳入,因?yàn)檫@是驅(qū)動(dòng)整個(gè)pipeline所需要的數(shù)據(jù), // 一般通過(guò)外部調(diào)用方的參數(shù)進(jìn)行封裝即可 public DefaultPipeline(Request request) { this.request = request; } // 這里我們可以看到,每一層級(jí)的調(diào)用都是通過(guò)HandlerContext.invokeXXX(head)的方式進(jìn)行的, // 也就是說(shuō)我們每一層級(jí)鏈的入口都是從頭結(jié)點(diǎn)開(kāi)始的,當(dāng)然在某些情況下,我們也需要從尾節(jié)點(diǎn)開(kāi)始鏈 // 的調(diào)用,這個(gè)時(shí)候傳入tail即可。 @Override public Pipeline fireTaskReceived() { HandlerContext.invokeTaskReceived(head, request); return this; } // 觸發(fā)任務(wù)過(guò)濾的鏈調(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; } // 這里通過(guò)實(shí)現(xiàn)InitializingBean接口來(lái)達(dá)到初始化Pipeline的目的,可以看到,這里初始的時(shí)候 // 我們通過(guò)ApplicationContext實(shí)例化了兩個(gè)HandlerContext對(duì)象,然后將head.next指向tail節(jié)點(diǎn), // 將tail.prev指向head節(jié)點(diǎn)。也就是說(shuō),初始時(shí),整個(gè)鏈只有頭結(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初始化一個(gè)HandlerContext private HandlerContext newContext(Handler handler) { HandlerContext context = this.context.getBean(HandlerContext.class); context.handler = handler; return context; } // 注入ApplicationContext對(duì)象 @Override public void setApplicationContext(ApplicationContext applicationContext) { this.context = applicationContext; } }
關(guān)于defaultPipeline的實(shí)現(xiàn),有以下幾點(diǎn)需要說(shuō)明:
defaultpipeline 使用@compoment和@scope("prototype")注解進(jìn)行了標(biāo)注,當(dāng)前一個(gè)注解用于將其聲明為一個(gè)spring容器所管理的bean,而后一個(gè)注解則用于表征defaultPipeline是個(gè)多例類型,很明顯的,這里的pipeLine是有狀態(tài)的。這里需要進(jìn)行說(shuō)明的是,'有狀態(tài)'主要是因?yàn)槲覀兛赡軙?huì)根據(jù)業(yè)務(wù)情況的動(dòng)態(tài)的調(diào)整整個(gè)鏈的節(jié)點(diǎn)情況,而且這里的request和task對(duì)象都是與具體的業(yè)務(wù)相關(guān)的,因?yàn)楸仨毬暶鳛閜rototype類型;
上面的示例中,request對(duì)象是通過(guò)構(gòu)造pipeline對(duì)象的時(shí)候傳進(jìn)來(lái)的,而task對(duì)象則是在pipeline的流轉(zhuǎn)過(guò)程中生成的,這里比如通過(guò)完成filterTaskReceived()鏈的調(diào)用之后,就需要通過(guò)外部請(qǐng)求request得到一個(gè)task對(duì)象,從而進(jìn)行后續(xù)的處理;
對(duì)于后續(xù)寫(xiě)業(yè)務(wù)代碼的人而言,其只需要實(shí)現(xiàn)一個(gè)Handler接口即可,無(wú)需要處理鏈相關(guān)的所有邏輯,以為我們需要獲取到所有實(shí)現(xiàn)Handler接口的bean;
將實(shí)現(xiàn)了Handler接口的bean通過(guò)Handlercontext進(jìn)行封裝,然后將其添加到pipeline中
這里的第一個(gè)問(wèn)題好處理,因?yàn)橥ㄟ^(guò)ApplicationContext就可以獲取實(shí)現(xiàn)了某個(gè)接口的所有bean,而第二個(gè)問(wèn)題我們可以通過(guò)聲明了BeanPostProcessoor接口的類來(lái)實(shí)現(xiàn)。如下是具體的實(shí)現(xiàn)代碼:
verride public void setApplicationContext(ApplicationContext applicationContext) { this.context = applicationContext; } } 關(guān)于DefaultPipeline的實(shí)現(xiàn),主要有如下幾點(diǎn)需要說(shuō)明: DefaultPipeline使用@Component和@Scope("prototype")注解進(jìn)行了標(biāo)注,前一個(gè)注解用于將其聲明為一個(gè)Spring容器所管理的bean,而后一個(gè)注解則用于表征DefaultPipeline是一個(gè)多例類型的,很明顯,這里的Pipeline是有狀態(tài)的。這里需要進(jìn)行說(shuō)明的是,"有狀態(tài)"主要是因?yàn)槲覀兛赡軙?huì)根據(jù)業(yè)務(wù)情況動(dòng)態(tài)的調(diào)整個(gè)鏈的節(jié)點(diǎn)情況,而且這里的Request和Task對(duì)象都是與具體的業(yè)務(wù)相關(guān)的,因而必須聲明為prototype類型; 上面的示例中,Request對(duì)象是通過(guò)構(gòu)造Pipeline對(duì)象的時(shí)候傳進(jìn)來(lái)的,而Task對(duì)象則是在Pipeline的流轉(zhuǎn)過(guò)程中生成的,這里比如通過(guò)完成fireTaskReceived()鏈的調(diào)用之后,就需要通過(guò)外部請(qǐng)求Request得到一個(gè)Task對(duì)象,從而進(jìn)行整個(gè)Pipeline的后續(xù)處理; 這里我們已經(jīng)實(shí)現(xiàn)了Pipeline,HandlerContext和Handler,知道這些bean都是被Spring所管理的bean,那么我們接下來(lái)的問(wèn)題主要在于如何進(jìn)行整個(gè)鏈的組裝。這里的組裝方式比較簡(jiǎn)單,其主要需要解決兩個(gè)問(wèn)題: 對(duì)于后續(xù)寫(xiě)業(yè)務(wù)代碼的人而言,其只需要實(shí)現(xiàn)一個(gè)Handler接口即可,而無(wú)需處理與鏈相關(guān)的所有邏輯,因而我們需要獲取到所有實(shí)現(xiàn)了Handler接口的bean; 將實(shí)現(xiàn)了Handler接口的bean通過(guò)HandlerContext進(jìn)行封裝,然后將其添加到Pipeline中。 這里的第一個(gè)問(wèn)題比較好處理,因?yàn)橥ㄟ^(guò)ApplicationContext就可以獲取實(shí)現(xiàn)了某個(gè)接口的所有bean,而第二個(gè)問(wèn)題我們可以通過(guò)聲明一個(gè)實(shí)現(xiàn)了BeanPostProcessor接口的類來(lái)實(shí)現(xiàn)。如下是其實(shí)現(xiàn)代碼: @Component public class HandlerBeanProcessor implements BeanPostProcessor, ApplicationContextAware { private ApplicationContext context; // 該方法會(huì)在一個(gè)bean初始化完成后調(diào)用,這里主要是在Pipeline初始化完成之后獲取所有實(shí)現(xiàn)了 // Handler接口的bean,然后通過(guò)調(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; } }
這里我們整個(gè)鏈路的維護(hù)工作就完成,可以看到,現(xiàn)在基本已經(jīng)實(shí)現(xiàn)了鏈?zhǔn)搅鞒炭刂?。這里需要說(shuō)明的一點(diǎn)是,上面的HandlerBeanProcessor.postProcessAfterInitialization()
方法的執(zhí)行是在InitializingBean.afterPropertySet()
方法之后執(zhí)行的,也就是說(shuō)這里的HandlerBeanProcessor
在執(zhí)行的時(shí)候,整個(gè)pipeline就是已經(jīng)完成初始化的了。下面我們來(lái)看下外部客戶端如何進(jìn)行這個(gè)鏈路流程的控制:
HandlerBeanProcessor在執(zhí)行時(shí),整個(gè)Pipeline是已經(jīng)初始化完成了的。下面我們來(lái)看一下外部客戶端如何進(jìn)行整個(gè)鏈?zhǔn)橇鞒痰目刂疲? @Service public class ApplicationService { @Autowired private ApplicationContext context; public void mockedClient() { Request request = new Request(); // request一般是通過(guò)外部調(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); } }
這里我們模擬一個(gè)客戶端的調(diào)用,首先創(chuàng)建了一個(gè)pipeline對(duì)象,然后依次調(diào)用各個(gè)層級(jí)的方法,并且這里我們使用try....finally結(jié)構(gòu)來(lái)保證Pipeline.fireAfterCompletion()
方法一定會(huì)執(zhí)行。如此我們就完成了整個(gè)責(zé)任鏈路模式的構(gòu)造。這里我們使用前面用到的時(shí)效性的filter來(lái)作為示例來(lái)實(shí)現(xiàn)一個(gè)Handler:
@Component public class DurationHandler implements Handler { @Override public void filterTask(HandlerContext ctx, Task task) { System.out.println("時(shí)效性檢驗(yàn)"); ctx.fireTaskFiltered(task); } }
關(guān)于這里具體的業(yè)務(wù)我們需要說(shuō)明的有如下幾點(diǎn):
改Handler必須使用@compoment注解來(lái)將其聲明為spring容器管理的bean,這樣我們前面實(shí)現(xiàn)的HandlerBeanProcessor
才能動(dòng)態(tài)的添加到整個(gè)pipeline中;
在每個(gè)Handler中,需要根據(jù)當(dāng)前的業(yè)務(wù)需要來(lái)實(shí)現(xiàn)具體的層級(jí)方法,比如這里是進(jìn)行時(shí)效性檢驗(yàn)的,就是"任務(wù)過(guò)濾"這一層級(jí)的邏輯,因?yàn)闀r(shí)效性檢驗(yàn)通過(guò)我們才能執(zhí)行這個(gè)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)前層級(jí)的鏈繼續(xù)往下傳遞,也就是這里的ctx.fireTaskFiltered(task);
方法的調(diào)用,我們可以看前面HandlerContext.fireXXX()
方法就是會(huì)獲取當(dāng)前節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn),然后進(jìn)行調(diào)用。如果根據(jù)業(yè)務(wù)需要,不需要將鏈往下傳遞,那么就不需要調(diào)用ctx.fireTaskFiltered(task);
看完上述內(nèi)容是否對(duì)您有幫助呢?如果還想對(duì)相關(guān)知識(shí)有進(jìn)一步的了解或閱讀更多相關(guān)文章,請(qǐng)關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝您對(duì)創(chuàng)新互聯(lián)的支持。
文章標(biāo)題:spring中怎么使用責(zé)任連模式
當(dāng)前鏈接:http://bm7419.com/article34/pcsise.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供服務(wù)器托管、網(wǎng)站排名、定制網(wǎng)站、企業(yè)網(wǎng)站制作、網(wǎng)站改版、網(wǎng)站設(shè)計(jì)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)