吳德,許凡
(三江學院計算機科學與工程學院,南京210012)
近年來,基于“互聯網+”模式的軟件系統變得越來越精致復雜[1],軟件需求和軟件架構的多元化,導致軟件開發過程中建模難度增加[2],其重要因素之一就是系統狀態隨著復雜的交互過程而變得更加多樣化。
在面向對象的編程中,如果出現大量的與類內部狀態轉換有關的邏輯時,傳統的解決方式為在代碼中增加大量的if…else或者switch等判斷語句。然而,這樣做一方面隨著狀態的增加代碼可能會不受控制(比如使用瀏覽器的歷史記錄、手工輸入鏈接以及模擬一次表單提交,等等),從而出現無法預期的狀態轉換錯誤,導致程序運行異常,給用戶造成損失;另一方面,這種做法將對象狀態的轉換與業務邏輯進行了緊密耦合,隨著規模的增大不利于系統的后期維護。
狀態機模式是處理這些情況的有效方法,它能處理任何順序的事件,并能提供有意義的響應——即使這些事件發生的順序和預計的不同。
Spring StateMachine是Spring提供的一個有限狀態機的框架。其主要功能是幫助開發者簡化狀態機的開發過程,讓狀態機結構更加層次化[3]。Spring StateMachine框架可將狀態機模式較為輕松地加入程序之中,提高編程的一致性和規范性。
有限狀態機(Finite State Machine,FSM),簡稱狀態機,是一種表示有限狀態以及在這些狀態之間的轉移和動作等行為的數學模型[4],廣泛應用于計算機領域。狀態機是一種圖形化的同步建模語言,具有并發性、層次性、良好的優先級搶占機制和通信機制[5]。
狀態機能采取某種操作來響應一個外部事件。具體采取的操作不僅取決于接收到的事件,還取決于各個事件的相對發生順序。之所以能做到這一點,是因為機器能跟蹤一個內部狀態,它會在收到事件后進行狀態更新。也就是說,為一個事件而采取的響應行動不僅取決于事件本身,還取決于其內部狀態。因此,任何邏輯都可建模成一系列事件/狀態組合。
驅動狀態機的是觸發器,這些觸發器基于事件或定時器。可以通過發送事件,或者請求當前狀態來與狀態機進行交互。
狀態機中的幾個重要概念:
(1)狀態:用于模擬事物在條件不變時情況相對穩定的抽象概念,是狀態機的主要實體,狀態的變化主要由事件驅動。
(2)事件:向狀態機發送的實體,用來驅動狀態機各種各樣的變化。
(3)行為:象征著從“源狀態”向“目標狀態”的轉換,伴隨著事件的發送,行為會進行特定的響應,實現對應的功能。
(4)初始狀態:狀態機被創建時的特殊狀態,總是伴隨著狀態機的初始化。
(5)結束狀態:也被稱為最終狀態,標志著狀態轉換已經完成。
Spring StateMachine是Spring提供給應用程序開發人員使用狀態機模型的一款輕量級框架。該框架提供了一整套與狀態機概念一一對應的工具類,用于模仿或者實現狀態機中每個實體對應的功能或者組件。
Spring StateMachine旨在提供以下功能:
(1)提供易于使用的、扁平的狀態機實例[6]。簡化狀態機構建的操作,使得開發人員更加容易地獲取狀態機對象。
(2)利用注解可以簡化復雜的狀態配置。降低代碼的復雜度,增加代碼的可讀性,提高開發效率。
(3)提供事件、行為的操作和使用。事件的觸發同時伴隨行為的發生,可以方便設置行為的具體內容。
(4)程序運行安全的適配器。保證程序安全運行,不會出現預料外的狀態改變。
Spring StateMachine配置流程如圖1所示。

圖1 Spring StateMachine配置流程圖
使用者首先需要按照狀態機模式的概念抽象出自己所需要的狀態以及事件。并為其定義好對應的枚舉類。例如:


根據狀態和事件進行配置,然后創建狀態機,獲取狀態機主要有通過狀態機生成器和使用注解自動注入兩種方式。每當事件發送時,狀態機都會監聽到,并且改變其對應的狀態,同時伴隨行為的發生。也可以自定義監聽器以滿足特定的需求。
本案例在電商訂單管理系統中加入Spring State Machine框架,嚴格控制訂單狀態走向。訂單最主要的狀態可以抽象為CREATED(已下單)、PICKED(已揀貨)、DELIVERED(已出庫)、SENT(已發貨)、RE?CEIVED(已收貨),根據具體場景還可能擴展為“已支付”、“已退貨”等。狀態遷移圖如圖2所示。

圖2 狀態轉移圖
系統采用Spring Boot框架進行搭建,使用Maven框架進行依賴管理,利用Spring MVC,實現傳統的MVC(Model View Controller)模式,數據庫持久層框架使用MyBatis,數據庫使用MySQL。
利用Spring StateMachine框架創建狀態機,將訂單所有的狀態抽象出來得到的狀態枚舉類為:

將所有管理事件抽象出來得到的枚舉類為:

將狀態和事件交由狀態機對象進行管理,在MVC的Controller層以及Service層發送事件,狀態機將觸發事件所對應的行為,將訂單狀態持久化存入數據庫中。總體框架如圖3所示。

圖3 系統技術架構圖
狀態機配置的具體步驟如下:
步驟1:定義狀態機的狀態和事件集合,將抽象好的狀態和事件分別創建對應的枚舉類。根據圖2的狀態轉移圖,對應的枚舉類如下:

步驟2:設置為狀態機的初始狀態,并配置狀態變化的流程。將“CREATED”設置為狀態機的初始狀態,并設置所有狀態的枚舉類。

步驟3:配置狀態變化的流程,例如:將“CREAT?ED”設置為源狀態,將“PICKED”設置為目標狀態,并關聯事件“PICK”,這樣當狀態機接收到狀態為源狀態“CREATED”的訂單以及事件“PICK”時就會自動獲取訂單的目標狀態“PICKED”,根據狀態轉移圖以此類推進行配置。
步驟4:設置自定義的持久化狀態機Handler以監聽系統內部訂單的狀態轉移,并設置伴隨狀態轉移觸發的行為。當事件被發送時,行為也會同時發生,在行為中對訂單狀態的改變進行持久化處理,例如:當“PICK”事件被監聽到時,訂單目標狀態“PICKED”就會被持久化至數據庫中。
在應用中合理使用狀態機設計模式可以增加程序的安全性,簡化代碼的編寫,增加代碼的可讀性。Spring StateMachine將狀態機模式以框架的形式引入到Web應用中,減輕了開發者的壓力,擴展了狀態機的功能,方便狀態機的監控以及持久化擴展,為開發者提供了更多的選擇。就Spring StateMachine而言,目前迭代的版本不多,并沒有得到充分的驗證,可能還存在一些未知的Bug,相信隨著信息技術的持續快速發展,Spring StateMachine會迎來更大的發展空間。