Spring基于狀態機squirrel-foundation簡單使用

squirrel-foundation的一些使用方法在百度上資料還是比較少,我是根據以下三個大佬寫的文章借鑒的,在這里記錄一下。
1、squirrel-foundation-demo
2、Squirrel使用(中文文檔)
3、squirrel-foundation狀態機的使用細節
我在這里直接粘貼代碼,便于自己之后理解。

 
  1. /**

  2. * 通過Spring創建StateMachineBuilder實例,通過buidler創建狀態機(單例)

  3. * 創建無類型化狀態機,簡化狀態機,防止過多泛化導致代碼不易閱讀(因為不太理解一些高級的使用)

  4. */

  5. public abstract class AbstractStateMachineEngine <T extends UntypedStateMachine> implements ApplicationContextAware {

  6. ?
  7. private ApplicationContext applicationContext;

  8. ?
  9. protected UntypedStateMachineBuilder stateMachineBuilder = null;

  10. ?
  11. @SuppressWarnings("unchecked")

  12. public AbstractStateMachineEngine() {

  13. //識別泛型參數

  14. Class<T> genericType = (Class<T>) GenericTypeResolver.resolveTypeArgument(getClass(),

  15. AbstractStateMachineEngine.class);

  16. stateMachineBuilder = StateMachineBuilderFactory.create(genericType, ApplicationContext.class);

  17. }

  18. ?
  19. //注入applicationContext,并在創建StateMachine實例時注入

  20. @Override

  21. public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

  22. this.applicationContext = applicationContext;

  23. }

  24. ?
  25. /**

  26. * 可以通過向OrderContext 上下文傳遞一些業務參數,比如orderId等等

  27. */

  28. public boolean fire(EOrderEvents event, OrderContext context) {

  29. T stateMachine = stateMachineBuilder.newUntypedStateMachine(

  30. context.geteOrder().getOrderStatus(),

  31. applicationContext);

  32. ?
  33. //由于StateMachine實例不是由Spring容器創建,所以這個過程中無法通過注解方式開啟事務(Spring沒有機會去創建事務代理),因此采用了編程式事務

  34. DataSourceTransactionManager transactionManager = (DataSourceTransactionManager)applicationContext.getBean("transactionManager");

  35. DefaultTransactionDefinition def = new DefaultTransactionDefinition();

  36. def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

  37. TransactionStatus status = transactionManager.getTransaction(def);

  38. try {

  39. stateMachine.fire(event, context);

  40. transactionManager.commit(status);

  41. //這里會返回狀態機是否出錯,如果出錯可用于通知Controller層,目前只會這樣簡單的操作

  42. return stateMachine.isError();

  43. } catch (Exception ex) {

  44. //用于事務回滾

  45. transactionManager.rollback(status);

  46. return true;

  47. }

  48. }

  49. }

 
  1. /**

  2. * 該類相當于監聽狀態變化,構造一些監聽方法實現一些邏輯代碼

  3. * @States 定義狀態列表,里面可以包含多個狀態

  4. * @State定義每個狀態,name狀態名稱,entryStateInit進入狀態時調用的方法,exitCallMethod 離開狀態是調用的方法,initialState 為true時,為默認狀態。

  5. * */

  6. @States({

  7. @State(name = "UNFOUND", entryCallMethod = "entryStateInit", exitCallMethod = "exitStateInit", initialState = true),

  8. @State(name = "USING", entryCallMethod = "entryStateWaitPay", exitCallMethod = "exitStateWaitPay"),

  9. @State(name = "COMPLETE", entryCallMethod = "entryStateWaitSend", exitCallMethod = "exitStateWaitSend"),

  10. @State(name = "REFUND", entryCallMethod = "entryStatePartSend", exitCallMethod = "exitStatePartSend"),

  11. @State(name = "NOUSE", entryCallMethod = "entryStatePartSend", exitCallMethod = "exitStatePartSend")

  12. })

  13. @Transitions({

  14. @Transit(from = "UNFOUND", to = "UNFOUND", on = "FOUND", callMethod = "createOrder"),

  15. @Transit(from = "UNFOUND", to = "USING", on = "SAOMA", callMethod = "submitOrder"),

  16. @Transit(from = "USING", to = "COMPLETE", on = "PAY", callMethod = "pay"),

  17. @Transit(from = "USING", to = "REFUND", on = "USING_REFUNDING", callMethod = "usingRefund"),

  18. @Transit(from = "COMPLETE", to = "REFUND", on = "COM_REFUNDING", callMethod = "comRefund")

  19. })

  20. //該地方向AbstractStateMachine傳遞的參數

  21. @StateMachineParameters(stateType = OrderStates.class, eventType = OrderEvents.class, contextType = OrderContext.class)

  22. public class SubmitOrderStateMachine extends AbstractStateMachine<UntypedStateMachine, Object, Object, Object> implements UntypedStateMachine {

  23. ?
  24. private OrderService OrderService;

  25. protected ApplicationContext applicationContext;

  26. ?
  27. //定義構造函數接受ApplicationContext注入([參看New State Machine Instance](http://hekailiang.github.io/squirrel/))

  28. public SubmitOrderStateMachine(ApplicationContext applicationContext) {

  29. this.applicationContext = applicationContext;

  30. // 通過applicationContext注入orderService,這樣就可以通過service操作數據庫

  31. OrderService = (OrderService) this.applicationContext.getBean("OrderService");

  32. }

  33. ?
  34. //創建訂單,依舊處于待使用狀態

  35. public void createOrder(OrderStates fromState, OrderStates toState, OrderEvents OrderEvents, OrderContext OrderContext) {

  36. //可以做一些創建訂單等等操作

  37. }

  38. ?
  39. //提交訂單

  40. public void submitOrder(OrderStates fromState, OrderStates toState, OrderEvents OrderEvents, OrderContext OrderContext) {

  41. }

  42. ?
  43. //支付訂單

  44. public void pay(OrderStates fromState, OrderStates toState, OrderEvents OrderEvents, OrderContext OrderContext) {

  45. }

  46. ?
  47. public void usingRefund(OrderStates fromState, OrderStates toState, OrderEvents OrderEvents, OrderContext OrderContext) {

  48. }

  49. ?
  50. public void comRefund(OrderStates fromState, OrderStates toState, OrderEvents OrderEvents, OrderContext OrderContext) {

  51. }

  52. ?
  53. /**

  54. * 如果實現這個方法,當上面方法執行出現錯誤時就會轉到這里來執行。

  55. * 但是由于自己是菜鳥,并不知道出錯后這里該如何通知到Controller層

  56. * 因此這里并未實現,具體的實現方法請參考官網

  57. */

  58. /*

  59. @Override

  60. protected void afterTransitionCausedException(Object fromState, Object toState, Object event, Object context) {

  61. //super.afterTransitionCausedException(fromState, toState, event, context);

  62. }*/

  63. }

還需要一個類集成AbstractStateMachineEngine,用于調用fire()方法。該類需要添加@Service注解,以便spring注入

 
  1. @Service

  2. public class OrderStateMachineEngine extends AbstractStateMachineEngine<SubmitOrderStateMachine>{

  3. ?
  4. }

Controller層使用:

 
  1. /**

  2. * 這里需要加上try**catch**,以便發生錯誤可方便執行下去

  3. */

  4. @RequestMapping(value="/modOrderStatus",method = {RequestMethod.POST})

  5. @ResponseBody

  6. public ResultEntity<Order> modOrderStatus(@RequestParam("event") String event,int code,Long orderId){

  7. ResultEntity<Order> resultEntity = new ResultEntity<Order>();

  8. try {

  9. Order Order = new Order();

  10. Order.setOrderStatus(OrderStates.getState(code));

  11. //向訂單上下文可添加一些邏輯參數,如:orderId

  12. OrderContext OrderContext = new OrderContext(Order, orderId);

  13. if(!orderStateMachineEngine.fire(OrderEvents.getEvent(event), OrderContext)) {

  14. resultEntity.setCode(1);

  15. resultEntity.setMessage("成功!");

  16. }else {

  17. resultEntity.setCode(0);

  18. resultEntity.setMessage("更新失敗,請重新嘗試!");

  19. }

  20. return resultEntity;

  21. } catch (Exception e) {

  22. e.printStackTrace();

  23. log.error(e);

  24. resultEntity.setCode(0);

  25. resultEntity.setMessage("更新失敗,請重新嘗試!");

  26. return resultEntity;

  27. }

  28. }

OrderContext類:

 
  1. /**

  2. * 訂單上下文

  3. * */

  4. public class OrderContext {

  5. ?
  6. public OrderContext(Order eOrder,Long orderId) {

  7. this.Order = Order;

  8. this.orderId = orderId;

  9. }

  10. ?
  11. public OrderContext() {

  12. }

  13. ?
  14. private Order Order;

  15. //邏輯參數

  16. private Long orderId;

  17. ?
  18. public Order getOrder() {

  19. return Order;

  20. }

  21. ?
  22. public void seteOrder(Order Order) {

  23. this.Order = Order;

  24. }

  25. ?
  26. public Long getOrderId() {

  27. return orderId;

  28. }

  29. ?
  30. public void setOrderId(Long orderId) {

  31. this.orderId = orderId;

  32. }

  33. }

OrderEvents枚舉:

 
  1. ?
  2. /**

  3. * 訂單狀態轉變事件

  4. * */

  5. public enum OrderEvents {

  6. FOUND, //創建訂單

  7. SAOMA, //提交訂單

  8. PAY, //付款

  9. USING_REFUNDING,

  10. COM_REFUNDING;

  11. ?
  12. public static OrderEvents getEvent(String event) {

  13. for (OrderEvents orderEvent : OrderEvents.values()) {

  14. if (orderEvent.name().equals(event)) {

  15. return orderEvent;

  16. }

  17. }

  18. return null;

  19. }

  20. }

OrderStatus枚舉:

 
  1. /**

  2. * 訂單狀態

  3. * */

  4. public enum OrderStates implements IEnum<Integer>{

  5. ?
  6. UNFOUND(1,"待使用"),

  7. USING(2,"正使用"),

  8. COMPLETE(3,"已完成"),

  9. REFUND(4,"退款"),

  10. NOUSE(5,"放棄訂單");

  11. ?
  12. private String desc;

  13. private int code;

  14. ?
  15. private OrderStates(int code,String desc) {

  16. this.code = code;

  17. this.desc = desc;

  18. }

  19. ?
  20. public String getDesc() {

  21. return desc;

  22. }

  23. public void setDesc(String desc) {

  24. this.desc = desc;

  25. }

  26. ?
  27. public int getCode() {

  28. return code;

  29. }

  30. public void setCode(int code) {

  31. this.code = code;

  32. }

  33. ?
  34. public static OrderStates getState(int code) {

  35. for (OrderStates orderState : OrderStates.values()) {

  36. if (orderState.ordinal()+1 == code) {

  37. return orderState;

  38. }

  39. }

  40. return null;

  41. }

  42. ?
  43. /**

  44. * 實現IEnum接口重寫的該方法

  45. * 該方法的作用就是表示返回的值,將要存儲在數據庫中

  46. * 和EnumValue注解作用一樣,在字段上EnumValue,就可不需要實現IEnum接口

  47. * */

  48. @Override

  49. public Integer getValue() {

  50. // TODO Auto-generated method stub

  51. return code;

  52. }

  53. ?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/386571.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/386571.shtml
英文地址,請注明出處:http://en.pswp.cn/news/386571.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

記得把每一次面試當做經驗積累,深夜思考

開頭 Android開發&#xff0c;假如開始沒有任何的開發經驗的話&#xff0c; 千萬不要著急&#xff0c;不要想著在短時間內就把一個語言學習好&#xff0c; 因為你之前沒有任何的學習經驗&#xff0c; 在這個過程中需要有耐心地學習完JAVA的基礎知識&#xff0c; 然后才開始踏上…

squirrel-foundation-demo

一個簡單的squirrel-foundation-demo 利用狀態機模擬一個訂單的支付過程。 squirrel-foundation沒有任何嚴重的依賴關系&#xff0c;因此基本上它應該是高度可嵌入的。squirrel-foundation沒有整合spring框架&#xff0c;所以首先要用spring集成squirrel-foundation。spring集成…

MongoDB學習目錄

MongoDB基礎篇 MongoDB 之 $ 關鍵字 python操作MongoDB 轉載于:https://www.cnblogs.com/yanzhi-1996/p/11095016.html

講的真透徹!還有人不知道什么是AndroidX的嗎?已拿offer入職

前言 春招已經接近尾聲了&#xff0c;不知道各位小伙伴有沒有收獲自己心儀的offer呢。筆者疫情被裁后在家LeetCode狂刷了800多題&#xff0c;加之自己以為工作總結的知識、經驗&#xff0c;系統化的整理了一下。在五一期間已經收獲了字節的offer。廢話不多說&#xff0c;下面是…

docker 啟動的 jenkins 中調用宿主機docker進行build

前言 期初有這個需求感覺就跟套娃一樣&#xff0c;你在docker 中調用docker&#xff0c;笑哭……這個也太逗了。 不過的確遇到了&#xff0c;因為jenkins 容器中沒有docker &#xff0c;所以在編譯 docker build 的時候 會出現 docker command 不存在。 好吧&#xff0c;解決他…

Codeforces 773D Perishable Roads 最短路 (看題解)

Perishable Roads 智商題&#xff0c; 不會啊。。 貼個官方題解 https://codeforces.com/blog/entry/51883 #include<bits/stdc.h> #define LL long long #define LD long double #define ull unsigned long long #define fi first #define se second #define mk make_p…

Rancher中的服務升級實驗

創建一個空的應用myAPP&#xff0c;在myAPP 應用中&#xff0c;創建一個服務nginx-test&#xff0c;包含2個容器副本&#xff0c;使用nginx:1.13.0鏡像。假設使用一段時期以后&#xff0c;nginx的版本升級到1.13.1了&#xff0c;如何將該服務的鏡像版本升級到新的版本&#xff…

該如何高效實用Kotlin?看這一篇就夠了!

前言 說起程序員人們的第一印象就是工資高、加班兇、話少錢多頭發少。再加上現在科技互聯網公司太吃香&#xff0c;bat、華為小米等公司程序員加班情況被廣泛傳播&#xff0c;程序員用生命在敲代碼的印象刻在了很多人的心里。 與其它行業一樣&#xff0c;凡是有高級和普通&…

apply()與call()

JavaScript中的每一個Function對象都有一個apply()方法和一個call()方法&#xff0c;它們的語法分別為&#xff1a; /*apply()方法*/ function.apply(thisObj[, argArray])/*call()方法*/ function.call(thisObj[, arg1[, arg2[, [,...argN]]]]); 它們各自的定義&#xff1a; a…

Java基于redis實現分布式鎖(SpringBoot)

前言 分布式鎖&#xff0c;其實原理是就是多臺機器&#xff0c;去爭搶一個資源&#xff0c;誰爭搶成功&#xff0c;那么誰就持有了這把鎖&#xff0c;然后去執行后續的業務邏輯&#xff0c;執行完畢后&#xff0c;把鎖釋放掉。 可以通過多種途徑實現分布式鎖&#xff0c;例如…

請談下Android消息機制,復習指南

談起Android框架體系架構&#xff0c;我先提個問&#xff1a;什么是Android框架體系架構 &#xff1f; Android系統構架是安卓系統的體系結構&#xff0c;android的系統架構和其操作系統一樣&#xff0c;采用了分層的架構&#xff0c;共分為四層&#xff0c;從高到低分別是And…

SVN Cannot merge into a working copy that has local modifications

我嘗試了 主支&#xff0c;分支都提交&#xff0c;但是依然無法合并。 最終&#xff0c;我在服務器上將分支刪除&#xff0c;然后主支在拷貝過去。 一&#xff0c;打開服務器資源 二&#xff0c;刪除分支 三&#xff0c;拷貝主支到分支 四&#xff0c;刷新分支&#xff0c;就能…

資深Android開發帶你入門Framework,再不刷題就晚了!

想要成為一名優秀的Android開發&#xff0c;你需要一份完備的知識體系&#xff0c;在這里&#xff0c;讓我們一起成長為自己所想的那樣。 本文參考了目前大部分 Android 應用啟動優化的方案&#xff0c;將大家的方案做一個匯總&#xff0c;如果你有這方面的需求&#xff0c;只…

K8S相關內容

常用工具&#xff1a;docker linux k8s kubeadm 概念 etcd 數據庫 類似redis api server 接口對外提供api 調用 可以命令 kubectl 或者 kube-proxy&#xff0c;能訪問etcd&#xff0c;事件總線 scheduler 調度決策的組件 掌握新的情況&#xff0c;進行決策及分布pod放在哪些n…

資深Android開發帶你入門Framework,架構師必備技能

開頭 先說一下我大概的情況吧。渣本畢業&#xff0c;工作已經有快兩年了&#xff0c;從高中就開始玩小破站。無論是學習還是日常放松都是在b站。大學主學的軟件技術專業&#xff0c;所以&#xff0c;進大學校門那一刻起&#xff0c;去上海bilibili工作就在心里埋下了種子。在學…

Java——線程鎖,死鎖,等待喚醒機制

一、線程鎖 線程安全問題 其實&#xff0c;線程安全問題都是由全局變量及靜態變量引起的。若每個線程中對全局變量、靜態變量只有讀操作&#xff0c;而無寫操作&#xff0c;一般來說&#xff0c;這個全局變量是線程安全的&#xff1b;若有多個線程同時執行寫操作&#xff0c;…

資深大牛帶你了解源碼!關于Android程序員最近的狀況,大廠內部資料

前言 回顧一下自己這段時間的經歷&#xff0c;因公司突然通知裁員&#xff0c;我匆匆忙忙地出去面了幾家&#xff0c;但最終都沒有拿到offer&#xff0c;我感覺今年的寒冬有點冷。公司開始第二波裁員&#xff0c;我決定主動拿賠償走人。后續的面試過程我做了一些準備&#xff…

AE 新建項目(一)(持續更新,做到哪算哪)

開發環境 工具&#xff1a;Visual Studio 2012、ArcEngine10.4.1 語言&#xff1a;C# 開發步驟 1、打開Visual Studio 2012&#xff0c;選擇新建項目&#xff0c;創建一個.NET Framework4的&#xff0c;Windows窗體應用程序。取名Demo 2、工具箱中&#xff0c;拖一個splitConta…

基于redis分布式鎖實現的多線程并發程序

前兩個版本的代碼 都或多或少存在一定的問題&#xff0c;雖然可能微乎其微&#xff0c;但是程序需要嚴謹再嚴謹&#xff0c; 第一個版本問題&#xff1a; 局限于單機版&#xff0c;依賴于 Jvm的鎖 第二個版本問題&#xff1a; 極端情況下&#xff0c;解鎖邏輯的問題&#xf…

day15 Ui自動化元素的定位

day15 元素的定位Ui自動化元素的定位1、火狐瀏覽器安裝try xpath2、元素定位思路&#xff1a;&#xff08;1&#xff09;查看頁面元素&#xff0c;確認能夠唯一定位到元素的屬性&#xff0c;比如id&#xff0c;文案3、學習xpath cssSelector 手寫定位方式xpath&#xff08;xpat…