Spring基于状态机squirrel-foundation简单使用

吕晟睿
2023-12-01

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.  
 类似资料: