1.背景

1.1 spring statemachine是干啥用的

有限状态机(英语:finite-state machine,缩写:FSM),简称状态机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型。将状态和事件控制从不同的业务Service方法的if else中抽离出来。FSM的应用范围很广,对于有复杂状态流,扩展性要求比较高的场景都可以使用该模型。下面是状态机模型中的4个要素,即现态、条件、动作、次态。

现态:是指当前所处的状态。

条件:又称为“事件”。当一个条件被满足,将会触发一个动作,或者执行一次状态的迁移。

动作:条件满足后执行的动作。动作执行完毕后,可以迁移到新的状态,也可以仍旧保持原状态。动作不是必需的,当条件满足后,也可以不执行任何动作,直接迁移到新状态。

次态:条件满足后要迁往的新状态。“次态”是相对于“现态”而言的,“次态”一旦被激活,就转变成新的“现态”了。

状态机对于流程性、状态变化的场景,它就是一个清晰的表达方式,这就是它的好处。

2.入门案例

使用maven项目,首先引入包

pom.xml

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework.statemachine</groupId><artifactId>spring-statemachine-core</artifactId><version>1.2.0.RELEASE</version></dependency>
</dependencies>

配置文件

StateMachineConfig.java

package com.huaquan.securityguard.config;import com.huaquan.securityguard.enums.EventEnum;
import com.huaquan.securityguard.enums.StatusEnum;
import org.springframework.context.annotation.Configuration;
import org.springframework.statemachine.config.EnableStateMachine;
import org.springframework.statemachine.config.EnableStateMachineFactory;
import org.springframework.statemachine.config.EnumStateMachineConfigurerAdapter;
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;import java.util.EnumSet;/*** @author 陆杰* @since 0.1*/
@Configuration
@EnableStateMachine
public class StateMachineConfig extends EnumStateMachineConfigurerAdapter<StatusEnum, EventEnum> {/*** 初始化状态机状态*/@Overridepublic void configure(StateMachineStateConfigurer<StatusEnum, EventEnum> states) throws Exception {states.withStates()// 定义初始状态.initial(StatusEnum.UNCONNECTED)// 定义状态机状态.states(EnumSet.allOf(StatusEnum.class));}/*** 初始化状态迁移事件*/@Overridepublic void configure(StateMachineTransitionConfigurer<StatusEnum, EventEnum> transitions)throws Exception {transitions// 1.连接事件// 未连接 -> 已连接.withExternal().source(StatusEnum.UNCONNECTED).target(StatusEnum.START).event(EventEnum.CONNECT).and()// 2.更新事件// 已连接 -> 更新中.withExternal().source(StatusEnum.START).target(StatusEnum.UPDATE).event(EventEnum.UPDATE).and()// 更新过期人员.withExternal().source(StatusEnum.START).target(StatusEnum.UPDATE_EXPER).event(EventEnum.UPDATE_EXPER).and().withExternal().source(StatusEnum.UPDATE_EXPER).target(StatusEnum.END).event(EventEnum.UPDATE_SUCCESS).and()// 3.更新成功事件//更新中 -> 已完成.withExternal().source(StatusEnum.UPDATE).target(StatusEnum.END).event(EventEnum.UPDATE_SUCCESS).and()// 5.结束事件// 已完成 -> 未连接.withExternal().source(StatusEnum.END).target(StatusEnum.UNCONNECTED).event(EventEnum.END);}
}

StateMachineEventConfig.java

package com.huaquan.securityguard.config;import com.huaquan.securityguard.service.ISqliteService;import com.huaquan.securityguard.service.impl.InfoService;
import com.huaquan.securityguard.util.IApiUtil;
import com.huaquan.securityguard.util.ISeverUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.statemachine.annotation.OnTransition;
import org.springframework.statemachine.annotation.WithStateMachine;/*** 功能:状态机* 2019年6月22日  v0.1** @author 陆杰* @since 0.1*/
@WithStateMachine
public class StateMachineEventConfig {Logger logger = LoggerFactory.getLogger(InfoService.class);@Autowiredprivate ISqliteService iSqliteService;@Autowiredprivate InfoService infoService;@Autowiredprivate ISeverUtil iSeverUtil;@Autowiredprivate IApiUtil iApiUtil;@OnTransition(source = "UNCONNECTED", target = "START")public void connect() {iApiUtil.login();logger.info("连接事件, 未连接 -> 已连接");}@OnTransition(source = "START", target = "UPDATE")public void update() throws InterruptedException {logger.info("UpdateIncrease----");
//        iSqliteService.insertLogViewWithStartTime(iSeverUtil.timeLtoS(System.currentTimeMillis()));infoService.UpdateTheFailMessage();infoService.UpdateFromRemoteDB();Thread.sleep(2000);}@OnTransition(source = "START", target = "UPDATE_EXPER")public void upExperson() throws InterruptedException {logger.info("UpdateEx----");infoService.UpdateExPerson();Thread.sleep(2000);}@OnTransition(source = "UPDATE", target = "END")public void updateSuccess() {logger.info("update success!");}@OnTransition(source = "END", target = "UNCONNECTED")public void unConnectSuccess() {logger.info("connect cancel");}}

enums 枚举,状态机中表示状态

EventEnum.java

public enum EventEnum {//未连接UNCONNECTED,// 连接CONNECT,// 更新UPDATE,// 更新成功UPDATE_SUCCESS,// 更新过期人员UPDATE_EXPER,// 更新失败UPDATE_FAILED,// 注销END;
}

StatusEnum.java

public enum StatusEnum {// 未连接UNCONNECTED,//开始START,// 更新中UPDATE,// 更新过期人员UPDATE_EXPER,// 结束END,
}

启动状态机

@Autowired
private StateMachine<StatusEnum, EventEnum> stateMachine;//引入状态机
stateMachine.start();
stateMachine.sendEvent(EventEnum.CONNECT);
stateMachine.sendEvent(EventEnum.UPDATE);
stateMachine.sendEvent(EventEnum.UPDATE_SUCCESS);
stateMachine.sendEvent(EventEnum.END);
stateMachine.sendEvent(EventEnum.UNCONNECTED);

(1)在实际使用中,应该是有很多任务的流程在同时跑,而不是像这个例子,全部任务共用一个流程,一个订单到EventEnum.UNCONNECTED状态了,其他任务就不能是UPDATE状态了。

(2)参数问题,我们做项目,不是为了看日志打出“---订单创建,待支付---”给我们玩的,而是要处理具体业务的,拿订单流程来说吧,订单号怎么传,状态改变时间怎么回数据库,等等问题其实都需要解决。

(3)存储问题,状态机如果有多个,需要的时候从哪去,暂时不需要了放哪去,这都是问题,所以存储状态机也是需要解决的。

3.多个状态机共存

在实际项目中一般性都会有多个状态机并发执行,在上面的例子中在程序中同时执行只能同时存在一个状态机,如果想要多个状态机并发就需要用到builer

StateMachineBuilder.Builder<OrderStates, OrderEvents> builder = StateMachineBuilder.builder();

OrderStateMachineBuilder.java

private final static String MACHINEID = "orderMachine";
public StateMachine<OrderStates, OrderEvents> build(BeanFactory beanFactory) throws Exception {StateMachineBuilder.Builder<OrderStates, OrderEvents> builder = StateMachineBuilder.builder();System.out.println("构建订单状态机");builder.configureConfiguration().withConfiguration().machineId(MACHINEID).beanFactory(beanFactory);builder.configureStates().withStates().initial(OrderStates.UNPAID).states(EnumSet.allOf(OrderStates.class));builder.configureTransitions().withExternal().source(OrderStates.UNPAID).target(OrderStates.WAITING_FOR_RECEIVE).event(OrderEvents.PAY).action(action()).and().withExternal().source(OrderStates.WAITING_FOR_RECEIVE).target(OrderStates.DONE).event(OrderEvents.RECEIVE);return builder.build();}

其中MACHINEID指向EventConfig

private final static String MACHINEID = "orderMachine";
  builder.configureConfiguration().withConfiguration().machineId(MACHINEID).beanFactory(beanFactory);

当然为了能调用到EventConfig,需要在EventConfig中注明它的名字,在1.x版本中不存在id这个字段,所以是无法关联的

@WithStateMachine(id="orderMachine")

在WithStateMachine中有两个字段

public @interface WithStateMachine {String name() default "stateMachine";String id() default "";
}

OrderEventConfig.java

@WithStateMachine(id="orderMachine")
public class OrderEventConfig {
private Logger logger = LoggerFactory.getLogger(getClass());/*** 当前状态UNPAID*/@OnTransition(target = "UNPAID")public void create() {logger.info("---订单创建,待支付---");}/*** UNPAID->WAITING_FOR_RECEIVE 执行的动作*/@OnTransition(source = "UNPAID", target = "WAITING_FOR_RECEIVE")public void pay(Message<OrderEvents> message) {System.out.println("传递的参数:" + message.getHeaders().get("order"));logger.info("---用户完成支付,待收货---");}/*** WAITING_FOR_RECEIVE->DONE 执行的动作*/@OnTransition(source = "WAITING_FOR_RECEIVE", target = "DONE")public void receive(Message<OrderEvents> message) {System.out.println("传递的参数:" + message.getHeaders().get("order"));System.out.println("传递的参数:" + message.getHeaders().get("otherObj"));logger.info("---用户已收货,订单完成---");}}

调用状态机代码,在调用状态机时候,现在每一次调用都会新建一个状态机并发运行。

StateMachine<OrderStates, OrderEvents> stateMachine = orderStateMachineBuilder.build(beanFactory);
System.out.println(stateMachine.getId());// 创建流程
stateMachine.start();// 触发PAY事件
stateMachine.sendEvent(OrderEvents.PAY);// 触发RECEIVE事件
//stateMachine.sendEvent(OrderEvents.RECEIVE);//用message传递数据
Order order = new Order(orderId, String.valueOf(Math.random()), "华师大科技园", "13435465465", "RECEIVE");
Message<OrderEvents> message = MessageBuilder.withPayload(OrderEvents.RECEIVE).setHeader("order", order).setHeader("otherObj", "otherObjValue").build();
stateMachine.sendEvent(message);// 获取最终状态
System.out.println("最终状态:" + stateMachine.getState().getId());

调用结果,因为这里的状态不是一个循环,如果不是并发创建新的状态机是无法第二次执行打印状态机执行的内容的。

2020-05-13 10:50:04.645  INFO 12176 --- [nio-9991-exec-1] tConfig$$EnhancerBySpringCGLIB$$928f5e35 : ---用户完成支付,待收货---
传递的参数:Order [id=null, userId=0.6601078768353066, address=华师大科技园, phoneNum=13435465465, state=RECEIVE]
传递的参数:otherObjValue
2020-05-13 10:50:04.648  INFO 12176 --- [nio-9991-exec-1] tConfig$$EnhancerBySpringCGLIB$$928f5e35 : ---用户已收货,订单完成---
最终状态:DONE
构建订单状态机
orderMachine
2020-05-13 10:50:09.395  INFO 12176 --- [nio-9991-exec-2] tConfig$$EnhancerBySpringCGLIB$$928f5e35 : ---订单创建,待支付---
2020-05-13 10:50:09.396  INFO 12176 --- [nio-9991-exec-2] o.s.s.support.LifecycleObjectSupport     : started org.springframework.statemachine.support.DefaultStateMachineExecutor@321218cf
2020-05-13 10:50:09.396  INFO 12176 --- [nio-9991-exec-2] o.s.s.support.LifecycleObjectSupport     : started DONE UNPAID WAITING_FOR_RECEIVE  / UNPAID / uuid=e9b620a5-cfe1-4018-b0d0-f5c14046f760 / id=orderMachine
DefaultStateContext [stage=TRANSITION, message=GenericMessage [payload=PAY, headers={id=36d3ed81-88ce-8524-db84-a791a258b891, timestamp=1589338209396}], messageHeaders={id=5cb640ed-3d05-972e-a291-eb2a66377b66, _sm_id_=e9b620a5-cfe1-4018-b0d0-f5c14046f760, timestamp=1589338209396}, extendedState=DefaultExtendedState [variables={}], transition=AbstractTransition [source=ObjectState [getIds()=[UNPAID], getClass()=class org.springframework.statemachine.state.ObjectState, hashCode()=1159188520, toString()=AbstractState [id=UNPAID, pseudoState=org.springframework.statemachine.state.DefaultPseudoState@1546ee, deferred=[], entryActions=[], exitActions=[], stateActions=[], regions=[], submachine=null]], target=ObjectState [getIds()=[WAITING_FOR_RECEIVE], getClass()=class org.springframework.statemachine.state.ObjectState, hashCode()=836740284, toString()=AbstractState [id=WAITING_FOR_RECEIVE, pseudoState=null, deferred=[], entryActions=[], exitActions=[], stateActions=[], regions=[], submachine=null]], kind=EXTERNAL, guard=null], stateMachine=DONE UNPAID WAITING_FOR_RECEIVE  / UNPAID / uuid=e9b620a5-cfe1-4018-b0d0-f5c14046f760 / id=orderMachine, source=null, target=null, sources=null, targets=null, exception=null]
传递的参数:null
2020-05-13 10:50:09.397  INFO 12176 --- [nio-9991-exec-2] tConfig$$EnhancerBySpringCGLIB$$928f5e35 : ---用户完成支付,待收货---
传递的参数:Order [id=null, userId=0.5339466950886407, address=华师大科技园, phoneNum=13435465465, state=RECEIVE]
传递的参数:otherObjValue
2020-05-13 10:50:09.397  INFO 12176 --- [nio-9991-exec-2] tConfig$$EnhancerBySpringCGLIB$$928f5e35 : ---用户已收货,订单完成---
最终状态:DONE

4.多种状态机共存

在实际需求中,一个程序可能有不同种类的状态机,服务不同的需求所以往往需要多个状态机,在实际操作中,我们只需要把创建状态机的步骤再做一遍取不同的名字就可以在一个程序内创建不同的状态机了。

在builder中根据需求各自创建config

private final static String MACHINEID = "orderMachine";public StateMachine<OrderStates, OrderEvents> build(BeanFactory beanFactory) throws Exception {StateMachineBuilder.Builder<OrderStates, OrderEvents> builder = StateMachineBuilder.builder();System.out.println("构建订单状态机");builder.configureConfiguration().withConfiguration().machineId(MACHINEID).beanFactory(beanFactory);
...省略
private final static String MACHINEID = "formMachine";public StateMachine<FormStates, FormEvents> build(BeanFactory beanFactory) throws Exception {StateMachineBuilder.Builder<FormStates, FormEvents> builder = StateMachineBuilder.builder();System.out.println("构建表单状态机");builder.configureConfiguration().withConfiguration().machineId(MACHINEID).beanFactory(beanFactory);
...省略

各自声明对应的eventConfig

@WithStateMachine(id="orderMachine")
public class OrderEventConfig {
...省略
@WithStateMachine(id="formMachine")
public class FormEventConfig {

分别执行不同的状态机

@RequestMapping("/testOrderState")public void testOrderState(String orderId) throws Exception {StateMachine<OrderStates, OrderEvents> stateMachine = orderStateMachineBuilder.build(beanFactory);System.out.println(stateMachine.getId());// 创建流程stateMachine.start();// 触发PAY事件stateMachine.sendEvent(OrderEvents.PAY);// 触发RECEIVE事件stateMachine.sendEvent(OrderEvents.RECEIVE);// 获取最终状态System.out.println("最终状态:" + stateMachine.getState().getId());}@RequestMapping("/testFormState")public void testFormState() throws Exception {StateMachine<FormStates, FormEvents> stateMachine = formStateMachineBuilder.build(beanFactory);System.out.println(stateMachine.getId());// 创建流程stateMachine.start();stateMachine.sendEvent(FormEvents.WRITE);stateMachine.sendEvent(FormEvents.CONFIRM);stateMachine.sendEvent(FormEvents.SUBMIT);// 获取最终状态System.out.println("最终状态:" + stateMachine.getState().getId());}

5.传递参数的Message

在企业开发中,数据在不同的业务间传输是最常见的工作,所以虽然我们的主架构是用的状态机,也就是从流程状态的角度来看待这个项目,但在具体业务中,每个状态的转变中会牵涉到各类业务,这些业务有些需要收到状态机变化的通知,需要把状态值传递给业务类和业务方法,同样的,在处理状态变化是,也需要获取业务数据,方便不同的业务在同一个状态变化环节做各自的业务,下面我们就讲下这个数据在spring statemachine里面的传递。

通过message传递,message只有两部分,header和payload

public interface Message<T> {T getPayload();MessageHeaders getHeaders();
}

传参数,在调用状态机时候,在message中可以传递对象,或者基础数据类型,在payload中装载状态即可

Message<OrderEvents> message = MessageBuilder.withPayload(OrderEvents.PAY).setHeader("order", order).setHeader("otherObj", "otherObjValue").build();
stateMachine.sendEvent(message);

与普通不装消息的设置状态对比

stateMachine.sendEvent(OrderEvents.PAY);

在接收端,即EventConfig中,方法中添加参数Message<OrderEvents> message,用于获取发过来的message

@OnTransition(source = "WAITING_FOR_RECEIVE", target = "DONE")
public void receive(Message<OrderEvents> message) {System.out.println("传递的参数:" + message.getHeaders().get("order"));System.out.println("传递的参数:" + message.getHeaders().get("otherObj"));logger.info("---用户已收货,订单完成---");
}

6.Statemachine持久化

持久化操作在实际业务中经常遇到,有时候需要对一个任务隔天处理,或者再久一点等到需要的时候再拿出来,这时候就要用到持久化操作。

6.1持久化在本地内存中(Map保存)

用唯一id作为key,把状态机保存到map表里面,在实际的业务中,自由存取

public class MachineMap {public static Map<String,StateMachine<OrderStates, OrderEvents>> orderMap = new HashMap<String,StateMachine<OrderStates, OrderEvents>>();public static Map<String,StateMachine<FormStates, FormEvents>> formMap = new HashMap<String,StateMachine<FormStates, FormEvents>>();}

关于StateMachinePersist和StateMachinePersister接口:

这两个接口名字很类似,很容易搞混,但下面的是有er的,包名也不同的。StateMachinePersister是可以直接保存StateMachine对象的,对于StateMachinePersist首先要实现它,然后再一个Config类里面转换成下面的StateMachinePersister,转换的代码就在上面的PersistConfig类里。

StateMachinePersist.class和StateMachinePersister.class对比

package org.springframework.statemachine;
public interface StateMachinePersist<S, E, T> {void write(StateMachineContext<S, E> context, T contextObj) throws Exception;StateMachineContext<S, E> read(T contextObj) throws Exception;
}
package org.springframework.statemachine.persist;
import org.springframework.statemachine.StateMachine;
public interface StateMachinePersister<S, E, T> {void persist(StateMachine<S, E> stateMachine, T contextObj) throws Exception;StateMachine<S, E> restore(StateMachine<S, E> stateMachine, T contextObj) throws Exception;
}

上述描述如何使用StateMachinePersist可能有点模糊,以下为具体步骤:

Step1:StateMachinePersist

@Component
public class InMemoryStateMachinePersist implements StateMachinePersist<OrderStates, OrderEvents, String> {private Map<String, StateMachineContext<OrderStates, OrderEvents>> map = new HashMap<String, StateMachineContext<OrderStates,OrderEvents>>();@Overridepublic void write(StateMachineContext<OrderStates, OrderEvents> context, String contextObj) throws Exception {map.put(contextObj, context);}@Overridepublic StateMachineContext<OrderStates, OrderEvents> read(String contextObj) throws Exception {return map.get(contextObj);}}

Step2:然后在 PersistConfig 中 注入:InMemoryStateMachinePersist

@Configuration
public class PersistConfig {@Autowiredprivate InMemoryStateMachinePersist inMemoryStateMachinePersist;/*** 注入StateMachinePersister对象* * @return*/@Bean(name="orderMemoryPersister")public StateMachinePersister<OrderStates, OrderEvents, String> getPersister() {return new DefaultStateMachinePersister<>(inMemoryStateMachinePersist);}}

Step3: 调用时根据bean注入

@Resource(name="orderMemoryPersister")
private StateMachinePersister<OrderStates, OrderEvents, String> orderMemorypersister;...StateMachine<OrderStates, OrderEvents> stateMachine = orderStateMachineBuilder.build(beanFactory);
stateMachine.start();//发送PAY事件
stateMachine.sendEvent(OrderEvents.PAY);
Order order = new Order();
order.setId(id);//持久化stateMachine
orderMemorypersister.persist(stateMachine, order.getId());...//取数据
StateMachine<OrderStates, OrderEvents> stateMachine = orderStateMachineBuilder.build(beanFactory);
orderMemorypersister.restore(stateMachine, id);
System.out.println("恢复状态机后的状态为:" + stateMachine.getState().getId());

6.2持久化到redis

pom.xml 依赖

<!-- redis持久化状态机 --><dependency><groupId>org.springframework.statemachine</groupId><artifactId>spring-statemachine-redis</artifactId><version>1.2.9.RELEASE</version></dependency>

redis配置

# REDIS (RedisProperties)
# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器地址
spring.redis.host=localhost
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.pool.max-wait=-1
# 连接池中的最大空闲连接
spring.redis.pool.max-idle=8
# 连接池中的最小空闲连接
spring.redis.pool.min-idle=0
# 连接超时时间(毫秒)
spring.redis.timeout=0

跟上面map存储一样,在配置文件内配置redis信息

PersistConfig.java

@Autowired
private RedisConnectionFactory redisConnectionFactory;.../*** 注入RedisStateMachinePersister对象* * @return*/
@Bean(name = "orderRedisPersister")
public RedisStateMachinePersister<OrderStates, OrderEvents> redisPersister() {return new RedisStateMachinePersister<>(redisPersist());
}/*** 通过redisConnectionFactory创建StateMachinePersist* * @return*/
public StateMachinePersist<OrderStates, OrderEvents,String> redisPersist() {RedisStateMachineContextRepository<OrderStates, OrderEvents> repository =new RedisStateMachineContextRepository<>(redisConnectionFactory);return new RepositoryStateMachinePersist<>(repository);
}

调用

@RequestMapping("/testRedisPersister")
public void testRedisPersister(String id) throws Exception {StateMachine<OrderStates, OrderEvents> stateMachine = orderStateMachineBuilder.build(beanFactory);stateMachine.start();Order order = new Order();order.setId(id);//发送PAY事件Message<OrderEvents> message = MessageBuilder.withPayload(OrderEvents.PAY).setHeader("order", order).build();stateMachine.sendEvent(message);//持久化stateMachineorderRedisPersister.persist(stateMachine, order.getId());
}@RequestMapping("/testRedisPersisterRestore")
public void testRestore(String id) throws Exception {StateMachine<OrderStates, OrderEvents> stateMachine = orderStateMachineBuilder.build(beanFactory);orderRedisPersister.restore(stateMachine, id);System.out.println("恢复状态机后的状态为:" + stateMachine.getState().getId());
}

7.statement伪持久化和中间段状态机

在实际的企业开发中,不可能所有情况都是从头到尾的按状态流程来,会有很多意外,比如历史数据,故障重启后的遗留流程......,所以这种可以任意调节状态的才是我们需要的状态机。

简而言之就是直接拿到状态机的一个中间过成,并可以继续执行。

回到persisit的实现类,既然目的是为了拿到一个中间段的状态机,那么就没有必要存当前状态了

@Component
public class OrderStateMachinePersist implements StateMachinePersist<OrderStates, OrderEvents, Order> {@Overridepublic void write(StateMachineContext<OrderStates, OrderEvents> context, Order contextObj) throws Exception {//这里不做任何持久化工作}@Overridepublic StateMachineContext<OrderStates, OrderEvents> read(Order contextObj) throws Exception {StateMachineContext<OrderStates, OrderEvents> result = new DefaultStateMachineContext<OrderStates, OrderEvents>(OrderStates.valueOf(contextObj.getState()), null, null, null, null, "orderMachine");return result;}
}

跟之前的步骤一样把persist注入到config文件中

@Configuration
public class PersistConfig {
@Autowiredprivate OrderStateMachinePersist orderStateMachinePersist;
@Bean(name="orderPersister")public StateMachinePersister<OrderStates, OrderEvents, Order> orderPersister() {return new DefaultStateMachinePersister<OrderStates, OrderEvents, Order>(orderStateMachinePersist);}
}

在执行的地方用通过persisiter拿到操作类

@RestController
@RequestMapping("/statemachine")
public class StateMachineController {@Resource(name="orderPersister")private StateMachinePersister<OrderStates, OrderEvents, Order> persister;@RequestMapping("/testOrderRestore")public void testOrderRestore(String id) throws Exception {StateMachine<OrderStates, OrderEvents> stateMachine = orderStateMachineBuilder.build(beanFactory);//订单Order order = new Order();order.setId(id);order.setState(OrderStates.WAITING_FOR_RECEIVE.toString());//恢复persister.restore(stateMachine, order);System.out.println("恢复后的状态:" + stateMachine.getState().getId());stateMachine.sendEvent(OrderEvents.RECEIVE);//查看恢复后状态机的状态System.out.println("执行下一步后的状态:" + stateMachine.getState().getId());}
}
构建订单状态机
恢复后的状态:WAITING_FOR_RECEIVE
传递的参数:null
传递的参数:null
执行下一步后的状态:DONE

statemachine简介及简单应用相关推荐

  1. Spring AOP 简介以及简单用法

    Spring AOP 简介以及简单用法 如果你去面试java开发, 那么Spring的AOP和DI几乎是必问的问题. 那么AOP是什么呢? 一. AOP 所谓Aop就是 Aspect-Oriented ...

  2. 重要性采样(Importance Sampling)简介和简单样例实现

    重要性采样(Importance Sampling)简介和简单样例实现 在渲染领域,重要性采样这个术语是很常见的,但它究竟是什么呢?我们首先考虑这样的一种情况: 如果场景里有一点P,我们想计算P点的最 ...

  3. ONENET平台简介及简单的接入方法

    ONENET平台简介及简单的接入方法 OneNET是中国移动物联网有限公司响应"大众创新.万众创业"以及基于开放共赢的理念,面向公共服务自主研发的开放云平台,为各种跨平台物联网应用 ...

  4. knockout.js的简介和简单使用

    1.knockout简介 knockout是一个轻量级的UI类库,通过MVVM模式使JavaScript前端UI简单化 knockout有四大重要概念: 1)声明式绑定:使用简明移读的语法很容易地将模 ...

  5. dbus的代码范例 linux_Dbus简介与简单的收发示例程序

    Dbus简介与简单的收发示例程序. D-BUS 是一个大有前途的消息总线和活动系统,正开始深入地渗透到 Linux® 桌面之中.了解创建它的原因.它的用途以及发展前景. D-BUS 本质上是 进程间通 ...

  6. matlab guide的简介和简单使用

    Matlab guide简介和简单使用 简介 快捷键 1.对其对象键 2.菜单编辑器 两种菜单的设计方法 3.Tab键顺序编辑器 4.属性检查器 gui数据管理机制 guide实例 实例一画图 实例二 ...

  7. 【gTest】gtest简介及简单使用

    [gTest]gtest简介及简单使用 gtest是一个跨平台(Liunx.Mac OS X.Windows.Cygwin.Windows CE and Symbian)的C++测试框架,有googl ...

  8. MongoDB自学笔记8--- 3.3 MongoDB Shell简介及简单使用

     3.3 MongoDB Shell简介及简单使用 mongoDB Shell是mongoDB自带的一个javascript shell,随mongoDB安装包一同发布.可以使用mongoDB she ...

  9. Spring Statemachine 简介

    Spring Statemachine 简介 Spring Statemachine是Spring官方提供的一个框架,供应用程序开发人员在Spring应用程序中使用状态机.支持状态的嵌套(substa ...

最新文章

  1. 使用Python和OpenCV对轮廓进行排序(从左到右,自上而下)
  2. html 的基本结构、标签(分类、关系)、文档类型、页面语言、字符集、语义化
  3. android判断和创建快捷方式(4.03测试通过)
  4. Radware:安全信息的传送可以加速网络攻击的防御
  5. selenium3 + python - page_source页面源码
  6. JavaScript自动设置IFrame高度(兼容各主流浏览器)
  7. java 发送邮件_Jenkins实现自动化邮件发送踩坑记录
  8. appium python unittest_appium+python+unittest自动化测试
  9. linux生成不能访问的文件夹,Linux ln创建软连接之后无法使用,无法whereis
  10. WebSocket科普
  11. Java Servlet 和JSP教程(2)
  12. LOJ 2312(洛谷 3733) 「HAOI2017」八纵八横——线段树分治+线性基+bitset
  13. 用c#语言制作ktv点歌系统,KTV点歌系统的设计与实现的设计和实现(C#,C/S,Access)
  14. java 与 php 区别或异同(整理、整合)
  15. 有源滤波器matlab/simulink 采用simulink搭建有源滤波器模型,有操作视频和报告资料,运行稳定,效果显著
  16. 论文笔记-《深度卷积神经网络的发展及其在计算机视觉领域的应用》
  17. 国外3个设计师插画等必备PNG免扣素材网站分享
  18. 有些路,只能一个人走。
  19. 【喜讯 · 喜讯】讲师自营销计划奖励又双叒叕来了!
  20. 微信小程序自适应图片的时候底部总有一条白色的空白区像一条线该怎么办呢?

热门文章

  1. linux 临时文件类型,Linux命令:文件管理--tmpwatch--删除临时文件
  2. apio2022 线上游记
  3. 二维数组打印杨辉三角
  4. 前端加油鸭!【FCC】JavaScript基础(1)
  5. 会计对象 会计科目 会计账户之间的关系
  6. 一个HIS开发者眼中的三甲医院就医流程
  7. 互联网大佬的“老赖”传说,前有贾跃亭、戴威,后有罗永浩、冯鑫
  8. 8月19日星期一 恒指 美原油 美黄金 走势分析
  9. 荷兰国旗问题的解决:额外空间复杂度O(1),时间复杂度O(N)
  10. 电脑html接口显示器不亮,VGA接口连接显示器电脑点不亮