https://blog.csdn.net/boxiong86/article/details/78434515
Activiti提供了命令攔截器的功能,外界對Activiti流程中各個實例進行操作,實際可以看作是對數據進行相應的操作,在此過程中,Activiti使用了設計模式中的命令模式,每一個操作數據庫的過程,均可被看作為一個命令,然后交由命令執行者去完成。除此之外,為了能讓使用者可以對這些命令進行相應的攔截(進行個性化處理),Activiti還使用了設計模式中的責任鏈模式,使用者可以添加相應的攔截器(責任鏈模式中的處理者)。
4.1命令模式
在GoF的設計模式中,命令模式屬於行為型模式,它把一個請求或者操作封裝到命令對象中,這些請求或者操作內容包括接收者信息,然后將該命令對象交由執行者執行,執行者不需要關心命令的接收人或者命令的具體內容,因為這些信息均被封裝到命令對象中。
命令模式是對命令的封裝。命令模式把發出命令的責任和執行命令的責任分割開,委派給不同的對象。每一個命令都是一個操作:請求的一方發出請求要求執行一個操作;接收的一方收到請求,並執行操作。命令模式允許請求的一方和接收的一方獨立開來,使得請求的一方不必知道接收請求的一方的接口,更不必知道請求是怎么被接收,以及操作是否被執行、何時被執行,以及是怎么被執行的。
命令模式中涉及的角色以及其作用如下:
n 命令接口(Command):聲明執行操作的接口。
n 接口實現(ConcreteCommand):命令接口實現,需要保存接收者的相應操作,並執行相應的操作。
n 命令執行者(Invoker):要求命令執行此次請求。
n 命令接收人(Receiver):由命令的實現維護實例,並在命令執行時處理相應的任務。
接下來,編寫一個最簡單的命令模式
然后創建命令接收者
本例中命令接者只有一個實現,方法A(doSomething)打印“命令接收人執行命令A”,方法B(doSomethingB)打印“命令接收人執行命令B”,接下來創建命令執行者
注意命令執行者的實現中,調使用命令的execute方法,並將相應的命令接收人設置到命令的execute方法參數中。此處創建命令接收者的方式,可以使用其他的設計模式完成,例如工廠模式,單態模式等等,此處為了更加簡單,直接new一個CommandReceiver的實現類。接下來,為命令接口提供兩個實現CommandA和CommandB
CommandA的實現中,直接讓命令接收執行方法A(doSomethingA),CommandB的實現與CommandA類似,只是執行命令接收者的方法B(doSomethingB)。到此,命令模式的各個角色已經創建完畢,接下來編寫客戶端代碼,讓命令執行者執行相應的命令。
先創建一個命令執行者,然后創建兩個命令,並交由命令執行者執行,最終執行結果將輸出“命令接收人執行命令A”和“命令接收人執行命令B”。
現在了解了GoF的命令模式,在Activiti中,每一個數據庫的CRUD操作,均為一個命令的實現,然后交給Activiti的命令執行者執行。Activiti使用了一個CommandContext類作為命令接收者,該對象維護一系列的Manager對象,這些Manager對象就像J2EE中的DAO對象。除了命令接收者外,Activiti還使用一系列的CommandInterceptor(命令攔截器),這些命令攔截器扮演命令模式中的命令執行者角色。那么這些命令攔截器是如何工作的呢?接下來需要了解責任鏈模式。
4.2責任與命令模式一樣,
責任鏈模式也是GoF的設計模式之一,同樣也是行為型模式。該設計模式為了讓多個對象都有機會處理請求,從而避免了請求發送者和請求接收者之間的耦合。這些請求接收者將組成一條,並沿着這條鏈傳遞該請求,直到有一個對象處理這個請求為止,這就形成一條責任鏈。責任鏈模式有以下參與者:
n 請求處理者接口(Handler):定義一個處理請求的接口,可以實現后繼鏈。
n 請求處理者實現(ConcreteHandler):請求處理接口的實現,如果它可以處理請求,就處理,否則就將該請轉發給它的后繼者。鏈模式
定義了一個請求處理者的抽象類,並且定義了請求的處理方法,需要由子類實現,需要注意的是,處理請求方法(execute)的參數為一個Request對象,本例中的Request對象只是一個普通的類,若責任鏈模式結合命令模式一起使用的話,那么execute方法的參數可以是命令模式中的命令接口。除此之外,Handler還定義了一個next屬性,在這里表示下一任處理者的對象,此處提供setter方法,由客戶端決定下一任請求處理者是誰。
Request對象只有一個doSomething方法,如果將Request設置為一個接口的話,那么它也可以像命令模式的命令接口一樣(見命令模式的Command)有多個實現。
HandlerA繼承了Handler並且實現了execute方法,當該處理器處理完自己的事情后,再將請求交由下一任處理者繼續執行請求。在責任鏈中,可以新建多個這樣的請求處理者
除了若干個請求處理者的實現外,還需要新建一個真實的請求處理者,實際上就算再多這樣的請求處理者實現,依然沒有對請求作任何處理,只是交由下一任處理者執行,因此需要一個真實的請求處理者來終結這條責任鏈。
最終的請求處理者最終執行了請求,並且不再往下執行(不使用next屬性)。下面編寫客戶端代碼,使用這個責任鏈。
定義了一個請求處理者的集合,然后按照該集合順序通過setNext方法為每一個請求處理者設置下一任的請求處理者,setNext方法最后返回第一任處理者(HandlerA)。需要注意的是,由於定義了最終的請求處理者為ActualHandler,因此需要將其放到集合的最后,作為終止整個責任鏈的角色。最終運行順序為:“請求處理者A處理請求”,“請求處理者B處理請求”,“執行請求”。
4.3編寫自定義攔截器
前面講解了命令模式與責任鏈模式,Activiti的攔截器,就是結合這兩種設計模式,達到攔截器的效果,每次Activiti進行業務操作,都會封裝為一個Command放到責任鏈中執行。知道其原理后,可以在實現自定義配置類時,編寫自己的攔截器。首先編寫第一個攔截器實現
類InterceptorA實現CommandInterceptor接口,實現責任鏈模式時,在攔截器的execute方法中,執行完攔截器自己的程序后(輸出業務命令),會執行責任鏈的下一個攔截器的execute方法。了解責任鏈模式后,不難發現,此處的next就是攔截器中的下一任請求處理者,而此處的請求,則是命令模式中的Command接口,編寫的InterceptorA就是責任鏈模式中請求處理者的其中一個實現。
使用同樣的方式,創建攔截器B,與攔截器A類似,輸出字符串與業務命令,再將請求(此處為Command)交由下一執行者執行。完成了兩個攔截器后,再去實現父類的初始化攔截器方法,將我們的攔截器“侵入”到Activiti的責任鏈中,
initCommandInterceptors方法,用於初始化命令攔截器集合。我們的自定義集合,加上Activiti的默認集合,形成擁有多個攔截器集合,也就是一條責任鏈。Activiti的默認集合,會加入日志攔截器、createTransactionInterceptor方法返回的攔截器、包含業務操作的命令、事務攔截器。
部署了一個簡單的流程,此時運行該測試程序,可以看到攔截器打印的效果:
可以看到,每執行一個命令,都會經過我們定義的攔截器A和B。
項目中編寫了節點跳轉命令