public enum Events {
PAY, // 支付
RECEIVE // 收货
}
public enum States {
UNPAID, // 待支付
WAITING_FOR_RECEIVE, // 待收货
DONE // 结束
}
@Component
public class InMemoryStateMachinePersist implements StateMachinePersist<States, Events, String> {
private static HashMap<String, StateMachineContext<States, Events>> map = new HashMap<>();
@Override
public void write(StateMachineContext<States, Events> context, String contextObj) throws Exception {
map.put(contextObj, context);
}
@Override
public StateMachineContext<States, Events> read(String contextObj) throws Exception {
return map.get(contextObj);
}
}
@Configuration
public class PersistConfig {
@Autowired
private InMemoryStateMachinePersist inMemoryStateMachinePersist;
@Bean(name = "myPersister")
public StateMachinePersister<States, Events, String> getPersister() {
return new DefaultStateMachinePersister<>(inMemoryStateMachinePersist);
}
}
@Configuration
@EnableStateMachine(name = "machine1")
public class StateMachineConfig extends EnumStateMachineConfigurerAdapter<States, Events> {
private Logger logger = LoggerFactory.getLogger(getClass());
@Override
public void configure(StateMachineStateConfigurer<States, Events> states)
throws Exception {
states
.withStates()
.initial(States.UNPAID)
.states(EnumSet.allOf(States.class));
}
@Override
public void configure(StateMachineTransitionConfigurer<States, Events> transitions)
throws Exception {
transitions
.withExternal()
.source(States.UNPAID).target(States.WAITING_FOR_RECEIVE)
.event(Events.PAY)
.and()
.withExternal()
.source(States.WAITING_FOR_RECEIVE).target(States.DONE)
.event(Events.RECEIVE);
}
@Override
public void configure(StateMachineConfigurationConfigurer<States, Events> config)
throws Exception {
config
.withConfiguration()
.listener(listener());
}
@Bean
public StateMachineListener<States, Events> listener() {
return new StateMachineListenerAdapter<States, Events>() {
@Override
public void transition(Transition<States, Events> transition) {
if(transition.getTarget().getId() == States.UNPAID) {
logger.info("订单创建,待支付");
return;
}
if(transition.getSource().getId() == States.UNPAID
&& transition.getTarget().getId() == States.WAITING_FOR_RECEIVE) {
logger.info("用户完成支付,待收货");
return;
}
if(transition.getSource().getId() == States.WAITING_FOR_RECEIVE
&& transition.getTarget().getId() == States.DONE) {
logger.info("用户已收货,订单完成");
return;
}
}
};
}
}
@RestController
@SpringBootApplication
public class LibraTestApplication {
public static void main(String[] args) {
SpringApplication.run(LibraTestApplication.class, args);
}
@Resource(name = "machine1")
StateMachine<States, Events> stateMachine1;
@Resource(name = "myPersister")
private StateMachinePersister<States, Events, String> persister;
@GetMapping("/1")
public void get1(@RequestParam(name = "key") String key) throws Exception{
stateMachine1.start();
stateMachine1.sendEvent(Events.PAY);
persister.persist(stateMachine1, key);
stateMachine1.stop();
}
@GetMapping("/2")
public void get2(@RequestParam(name = "key") String key) throws Exception{
stateMachine1.sendEvent(Events.RECEIVE);
persister.persist(stateMachine1, key);
stateMachine1.stop();
}
@GetMapping("/3")
public void get3(@RequestParam(name = "key") String key) throws Exception{
persister.restore(stateMachine1, key);
if(stateMachine1.getState().getId() == States.WAITING_FOR_RECEIVE){
stateMachine1.sendEvent(Events.RECEIVE);
}else {
stateMachine1.sendEvent(Events.PAY);
}
stateMachine1.stop();
}
}
1、machine是线程非安全的,所以创建的时候需要通过工厂类StateMachineFactory产生、或者通过builder产生
2、状态需要被持久化,StateMachinePersist,持久化中的异常不会被主程序吃掉,会被抛出来
3、StateMachine流程配置config中的action,异常需要通过stateContext.getStateMachine().setStateMachineError()设置,才能在外层通过
stateContext.getStateMachine().hasStateMachineError()判断内部流程是否异常。因为action的异常会被吃掉,只能通过上下文传递。
使用Spring StateMachine框架实现状态机 - 简书