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.mzph.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…