最近,在工作中上级派了一个任务给我,叫我写下状态机。一开始我听了是直接懵逼的,我都不知道什么是状态机。后来听了业务需求后才慢慢弄懂,这个状态机的作用是修改订单状态,为了让业务代码能够高效复用。这又引出了第二问题了,要怎样实现状态机,是写一堆if-else判断吗?一开始我的想法就是这样,后来上网查了状态机,发现有个StateMachine框架,然后就去看了官方文档https://docs.spring.io/spring-statemachine/docs/2.0.2.RELEASE/reference/htmlsingle/#with-enablestatemachinefactory。当然期间在使用过程中也踩了不少的坑,就把自己一些心得写下来,当然自己没阅读过什么源码,只能是自己一些粗浅的见解而已。仅供参考。
这个流程图我是感觉非常重要的,要清楚每个状态的流转,和哪种事件会触发什么事件流转这都是很重要的。下面是我自己工作的一个状态流程图
.withExternal()
.source(TradeOrderStateMachineEnum.WAIT_FOR_PAY)
.target(TradeOrderStateMachineEnum.CLOSED)
.event(TradeOrderEvent.CLOSE).and()
这是配置规则,表示从WAIT_FOR_PAY->CLOSED,需要CLOSE事件来触发。这是比较简单的一种,没有guard判断,直接流转到CLOSED状态。
.withExternal()
.source(TradeOrderStateMachineEnum.WAIT_FOR_AUDIT)
.target(TradeOrderStateMachineEnum.WAIT_FOR_DELIVER)
.event(TradeOrderEvent.AUDIT).guard(tradeOrderGuardFactory.new TradeOrderGuard()).and()
下面一种,则是多了一个.guard(),这是判断,相当于java里面if的判断条件,这个自定义判断的类必须实现Guard接口,重写里面evaluate方法,这个方法就是返回boolean。值得一提的是,每个规则都可以配置action,可以直接在后面加上.action(),也可以用@WithStateMachine和@OnTransition两个注解配合用写下自己业务代码。这个action表示,满足整个链路规则后才要做的是。
.withChoice()
.source(TradeOrderStateMachineEnum.AUDIT_CHOICE)
.first(TradeOrderStateMachineEnum.COMPLETED, tradeOrderGuardFactory.new TradeOrderAuditChoiceGuard(),new TradeOrderChoiceAction())
.then(TradeOrderStateMachineEnum.WAIT_FOR_EVALUATE, tradeOrderGuardFactory.new TradeOrderAuditChoiceGuard2(),new TradeOrderChoiceAction())
.then(TradeOrderStateMachineEnum.WAIT_FOR_SIGN, tradeOrderGuardFactory.new TradeOrderAuditChoiceGuard3(),new TradeOrderChoiceAction())
.then(TradeOrderStateMachineEnum.WAIT_FOR_DELIVER, tradeOrderGuardFactory.new TradeOrderAuditChoiceGuard4(),new TradeOrderChoiceAction())
.last(TradeOrderStateMachineEnum.WAIT_FOR_AUDIT).and()
前面两种是比较简单的,一个事件只会流转到一个状态,上面这个就是比较复杂点,也是业务上经常会用,一个event会有几种状态,first-then-last,就相当于if-else if,只要满足一个guard判断就不会往下流转,注意这里有几个坑,后面说下的。
org.springframework.statemachine
spring-statemachine-starter
2.0.1.RELEASE
3.2 定义状态枚举和事件枚举
TradeOrderStateMachineEnum
public enum TradeOrderStateMachineEnum {
WAIT_FOR_PAY(10, "待付款"),
WAIT_FOR_AUDIT(20, "待评审"),
WAIT_FOR_DELIVER(30, "待发货"),
WAIT_FOR_SIGN(40, "待签收"),
WAIT_FOR_EVALUATE(45, "待评价"),
COMPLETED(98, "完成"),
CLOSED(99, "关闭"),
AUDIT_CHOICE(1000, "评审选择态"),
SIGN_CHOICE(1001, "签收选择态");
private final Integer value;
private final String desc;
private static final Map valueMap = (Map) Arrays.stream(values()).collect(Collectors.toMap(TradeOrderStateMachineEnum::getValue, Function.identity()));
private TradeOrderStateMachineEnum(Integer value, String desc) {
this.value = value;
this.desc = desc;
}
public Integer getValue() {
return this.value;
}
public String getDesc() {
return this.desc;
}
public static TradeOrderStateMachineEnum fromValue(Integer value) {
return (TradeOrderStateMachineEnum) Optional.ofNullable(valueMap.get(value)).orElseThrow(() -> {
return new RuntimeException("can not find the enum for this value: " + value);
});
}
}
TradeOrderEvent
public enum TradeOrderEvent {
PAY,//付款
CLOSE,//关闭订单
CANCEL,//取消数量
AUDIT,//评审
DELIVER,//发货
SIGN,//签收
EVALUATE;//评价
}
TradeOrderStateMachineBuilder
@Component
@EnableStateMachine(name= TradeOrderStateMachineBuilder.MACHINEID_TO)
public class TradeOrderStateMachineBuilder {
private static final TradeOrderGuardFactory tradeOrderGuardFactory= new TradeOrderGuardFactory();
@Autowired
private BeanFactory beanFactory;
private Logger logger = LoggerFactory.getLogger(getClass());
public final static String MACHINEID_TO = "MACHINEID_TO";//TO状态机
public StateMachine build() throws Exception {
StateMachine stateMachine = build(beanFactory);
logger.info("状态机ID:"+stateMachine.getId());
stateMachine.start();
return stateMachine;
}
/**
* 构建状态机
* -构建TO单状态机
* @param beanFactory
* @return
* @throws Exception
*/
public StateMachine build(BeanFactory beanFactory) throws Exception {
StateMachineBuilder.Builder builder = StateMachineBuilder.builder();
builder.configureConfiguration()
.withConfiguration()
.machineId(MACHINEID_TO)
.beanFactory(beanFactory);
builder.configureStates()
.withStates()
.initial(TradeOrderStateMachineEnum.WAIT_FOR_PAY)
.choice(TradeOrderStateMachineEnum.AUDIT_CHOICE)
.choice(TradeOrderStateMachineEnum.SIGN_CHOICE)
.states(EnumSet.allOf(TradeOrderStateMachineEnum.class));
builder.configureTransitions()
//支付后,从待付款到待审核
.withExternal()
.source(TradeOrderStateMachineEnum.WAIT_FOR_PAY)
.target(TradeOrderStateMachineEnum.WAIT_FOR_AUDIT)
.event(TradeOrderEvent.PAY).and()
//取消订单,从待付款到关闭
.withExternal()
.source(TradeOrderStateMachineEnum.WAIT_FOR_PAY)
.target(TradeOrderStateMachineEnum.CLOSED)
.event(TradeOrderEvent.CLOSE).and()
//取消数量,从待审核到审核选择态
.withExternal()
.source(TradeOrderStateMachineEnum.WAIT_FOR_AUDIT)
.target(TradeOrderStateMachineEnum.AUDIT_CHOICE)
.event(TradeOrderEvent.CANCEL).and()
//取消数量,从审核选择态->待发货,待签收,待评价,完成任意一种状态
.withChoice()
.source(TradeOrderStateMachineEnum.AUDIT_CHOICE)
.first(TradeOrderStateMachineEnum.COMPLETED, tradeOrderGuardFactory.new TradeOrderAuditChoiceGuard(),new TradeOrderChoiceAction())
.then(TradeOrderStateMachineEnum.WAIT_FOR_EVALUATE, tradeOrderGuardFactory.new TradeOrderAuditChoiceGuard2(),new TradeOrderChoiceAction())
.then(TradeOrderStateMachineEnum.WAIT_FOR_SIGN, tradeOrderGuardFactory.new TradeOrderAuditChoiceGuard3(),new TradeOrderChoiceAction())
.then(TradeOrderStateMachineEnum.WAIT_FOR_DELIVER, tradeOrderGuardFactory.new TradeOrderAuditChoiceGuard4(),new TradeOrderChoiceAction())
.last(TradeOrderStateMachineEnum.WAIT_FOR_AUDIT).and()
//审核后,从待审核到待发货
.withExternal()
.source(TradeOrderStateMachineEnum.WAIT_FOR_AUDIT)
.target(TradeOrderStateMachineEnum.WAIT_FOR_DELIVER)
.event(TradeOrderEvent.AUDIT).guard(tradeOrderGuardFactory.new TradeOrderGuard()).and()
//发货后,从待发货到待签收
.withExternal()
.source(TradeOrderStateMachineEnum.WAIT_FOR_DELIVER)
.target(TradeOrderStateMachineEnum.WAIT_FOR_SIGN)
.event(TradeOrderEvent.DELIVER).guard(tradeOrderGuardFactory.new TradeOrderGuard()).and()
//签收后,从待签收到待签收选择态
.withExternal()
.source(TradeOrderStateMachineEnum.WAIT_FOR_SIGN)
.target(TradeOrderStateMachineEnum.SIGN_CHOICE)
.event(TradeOrderEvent.SIGN).and()
//签收后,从待签收选择态到待评价或者到已完成
.withChoice()
.source(TradeOrderStateMachineEnum.SIGN_CHOICE)
.first(TradeOrderStateMachineEnum.WAIT_FOR_EVALUATE, tradeOrderGuardFactory.new TradeOrderSignChoiceGuard(),new TradeOrderChoiceAction())
.then(TradeOrderStateMachineEnum.COMPLETED, tradeOrderGuardFactory.new TradeOrderSignChoiceGuard2(),new TradeOrderChoiceAction())
.last(TradeOrderStateMachineEnum.WAIT_FOR_SIGN).and()
//评价后,从待评价到已完成
.withExternal()
.source(TradeOrderStateMachineEnum.WAIT_FOR_EVALUATE)
.target(TradeOrderStateMachineEnum.COMPLETED)
.event(TradeOrderEvent.EVALUATE);
return builder.build();
}
@Bean(name = "tradeOrderStateMachinePersister")
public StateMachinePersister getOrderPersister() {
return new DefaultStateMachinePersister<>(new StateMachinePersist() {
@Override
public void write(StateMachineContext context, TradeOrder contextObj) {
}
@Override
public StateMachineContext read(TradeOrder contextObj) {
StateMachineContext result = new DefaultStateMachineContext(TradeOrderStateMachineEnum.fromValue(contextObj.getOrderState()),
null, null, null, null, MACHINEID_TO);
return result;
}
;
});
}
}
这部分是可以优化,因为我看官网的文档,每个判断都要新建guard类重写evaluate方法。我不想建太多类,就集成一个类里面了。我本意是想用工厂模式想新建Guard类,但是本人开发经验不是很丰富。
TradeOrderGuardFactory
public class TradeOrderGuardFactory {
private static final String TRADE_ORDER = StateMachineHeaderNameConstants.TRADE_ORDER;
public class TradeOrderAuditChoiceGuard implements Guard {
@Override
public boolean evaluate(StateContext context) {
TradeOrder tradeOrder = context.getMessage().getHeaders().get(TRADE_ORDER, TradeOrder.class);
if(isAllSign(tradeOrder) && !StringUtils.isEmpty(tradeOrder.getBuyer().getBuyerTenantCode())){
return true;
}
return false;
}
}
public class TradeOrderAuditChoiceGuard2 implements Guard {
@Override
public boolean evaluate(StateContext context) {
TradeOrder tradeOrder = context.getMessage().getHeaders().get(TRADE_ORDER, TradeOrder.class);
if(isAllSign(tradeOrder) && StringUtils.isEmpty(tradeOrder.getBuyer().getBuyerTenantCode())){
return true;
}
return false;
}
}
public class TradeOrderAuditChoiceGuard3 implements Guard {
@Override
public boolean evaluate(StateContext context) {
TradeOrder tradeOrder = context.getMessage().getHeaders().get(TRADE_ORDER, TradeOrder.class);
if(isAllDeliver(tradeOrder)){
return true;
}
return false;
}
}
public class TradeOrderAuditChoiceGuard4 implements Guard {
@Override
public boolean evaluate(StateContext context) {
TradeOrder tradeOrder = context.getMessage().getHeaders().get(TRADE_ORDER, TradeOrder.class);
if(isAllAudit(tradeOrder) ){
return true;
}
return false;
}
}
public class TradeOrderSignChoiceGuard implements Guard {
@Override
public boolean evaluate(StateContext context) {
TradeOrder tradeOrder = context.getMessage().getHeaders().get(TRADE_ORDER, TradeOrder.class);
if(isAllSign(tradeOrder) && StringUtils.isEmpty(tradeOrder.getBuyer().getBuyerTenantCode())){
return true;
}
return false;
}
}
public class TradeOrderSignChoiceGuard2 implements Guard {
@Override
public boolean evaluate(StateContext context) {
TradeOrder tradeOrder = context.getMessage().getHeaders().get(TRADE_ORDER, TradeOrder.class);
if(isAllSign(tradeOrder) && !StringUtils.isEmpty(tradeOrder.getBuyer().getBuyerTenantCode())){
return true;
}
return false;
}
}
public class TradeOrderGuard implements Guard {
@Override
public boolean evaluate(StateContext context) {
boolean result=false;
System.out.println(context.getSource().getId());
System.out.println(context.getTarget().getId());
switch (context.getTarget().getId()) {
case WAIT_FOR_DELIVER:
return WAIT_FOR_DELIVER(context);
case WAIT_FOR_SIGN:
return WAIT_FOR_SIGN(context);
case SIGN_CHOICE:
return SIGN_CHOICE(context);
case WAIT_FOR_EVALUATE:
return WAIT_FOR_EVALUATE(context);
case COMPLETED:
return COMPLETED(context);
default:
break;
}
return result;
}
private boolean WAIT_FOR_DELIVER(StateContext context){
TradeOrder tradeOrder = context.getMessage().getHeaders().get(TRADE_ORDER, TradeOrder.class);
if(isAllAudit(tradeOrder)){
return true;
}
return false;
}
private boolean WAIT_FOR_SIGN(StateContext context){
TradeOrder tradeOrder = context.getMessage().getHeaders().get(TRADE_ORDER, TradeOrder.class);
if(isAllDeliver(tradeOrder)){
return true;
}
return false;
}
private boolean SIGN_CHOICE(StateContext context){
TradeOrder tradeOrder = context.getMessage().getHeaders().get(TRADE_ORDER, TradeOrder.class);
if(isAllSign(tradeOrder)){
return true;
}
return false;
}
private boolean WAIT_FOR_EVALUATE(StateContext context){
TradeOrder tradeOrder = context.getMessage().getHeaders().get(TRADE_ORDER, TradeOrder.class);
if(isAllSign(tradeOrder)&& StringUtils.isEmpty(tradeOrder.getBuyer().getBuyerTenantCode())){
return true;
}
return false;
}
private boolean COMPLETED(StateContext context){
TradeOrder tradeOrder = context.getMessage().getHeaders().get(TRADE_ORDER, TradeOrder.class);
if(isAllSign(tradeOrder)&& !StringUtils.isEmpty(tradeOrder.getBuyer().getBuyerTenantCode())){
return true;
}
return false;
}
}
private boolean isAllAudit(TradeOrder tradeOrder) {
for (TradeOrderDetail tradeOrderDetail : tradeOrder.getTradeOrderDetailList()) {
if(ObjectUtils.isEmpty(tradeOrderDetail.getCancelQty())){
tradeOrderDetail.setCancelQty(0);
}
if(ObjectUtils.isEmpty(tradeOrderDetail.getAuditQty())){
tradeOrderDetail.setAuditQty(0);
}
//待评审的数量
if(tradeOrderDetail.getItemQty()-tradeOrderDetail.getCancelQty()-tradeOrderDetail.getAuditQty()!=0){
return false;
}
}
return true;
}
private boolean isAllDeliver(TradeOrder tradeOrder) {
for (TradeOrderDetail tradeOrderDetail : tradeOrder.getTradeOrderDetailList()) {
if(ObjectUtils.isEmpty(tradeOrderDetail.getCancelQty())){
tradeOrderDetail.setCancelQty(0);
}
if(ObjectUtils.isEmpty(tradeOrderDetail.getDeliverQty())){
tradeOrderDetail.setDeliverQty(0);
}
//待评审的数量
if(tradeOrderDetail.getItemQty()-tradeOrderDetail.getCancelQty()-tradeOrderDetail.getDeliverQty()!=0){
return false;
}
}
return true;
}
private boolean isAllSign(TradeOrder tradeOrder) {
for (TradeOrderDetail tradeOrderDetail : tradeOrder.getTradeOrderDetailList()) {
if(ObjectUtils.isEmpty(tradeOrderDetail.getCancelQty())){
tradeOrderDetail.setCancelQty(0);
}
if(ObjectUtils.isEmpty(tradeOrderDetail.getCustSignQty())){
tradeOrderDetail.setCustSignQty(0);
}
//代签收的数量
if((tradeOrderDetail.getItemQty()-tradeOrderDetail.getCancelQty()-tradeOrderDetail.getCustSignQty()!=0)){
return false;
}
}
return true;
}
}
这里有用两种方式,一种是注解,另外一种是实现Action类重写execute方法,至于为什么用两种,后面会有说的,这也是其中一个坑。
TradeOrderChoiceAction
@Slf4j
public class TradeOrderChoiceAction implements Action {
private static final String TRADE_ORDER = StateMachineHeaderNameConstants.TRADE_ORDER;
@Override
public void execute(StateContext context) {
System.out.println(context.getTarget().getId());
switch (context.getTarget().getId()) {
case AUDIT_CHOICE:
AUDIT_CHOICE(context);
break;
case SIGN_CHOICE:
SIGN_CHOICE(context);
break;
default:
break;
}
}
private void SIGN_CHOICE(StateContext context) {
TradeOrder tradeOrder = context.getMessage().getHeaders().get(TRADE_ORDER, TradeOrder.class);
log.info("签收事件之前,订单的状态为:{}"+tradeOrder.getOrderState());
if(isAllSign(tradeOrder)){
//全部签收,并且是2C,则为待评价状态
if(StringUtils.isEmpty(tradeOrder.getBuyer().getBuyerTenantCode())){
tradeOrder.setOrderState(TradeOrderStateMachineEnum.WAIT_FOR_EVALUATE.getValue());
}else{
//全部签收,并且是2B,则为完成状态
tradeOrder.setOrderState(TradeOrderStateMachineEnum.COMPLETED.getValue());
}
}
log.info("签收事件之后,订单的状态为:{}"+tradeOrder.getOrderState());
}
private void AUDIT_CHOICE(StateContext context) {
TradeOrder tradeOrder = context.getMessage().getHeaders().get(TRADE_ORDER, TradeOrder.class);
log.info("取消数量事件之前,订单的状态为:{}"+tradeOrder.getOrderState());
//如果全部签收,则可能是待评价状态或者是完成状态
if(isAllSign(tradeOrder)){
//2C,则为待评价状态
if(StringUtils.isEmpty(tradeOrder.getBuyer().getBuyerTenantCode())){
tradeOrder.setOrderState(TradeOrderStateMachineEnum.WAIT_FOR_EVALUATE.getValue());
}else{
//2B,则为完成状态
tradeOrder.setOrderState(TradeOrderStateMachineEnum.COMPLETED.getValue());
}
}else if(isAllDeliver(tradeOrder)){
//如果全部发货,则为代签收状态
tradeOrder.setOrderState(TradeOrderStateMachineEnum.WAIT_FOR_SIGN.getValue());
}else if(isAllAudit(tradeOrder)){
//如果全部审核,则为待发货状态
tradeOrder.setOrderState(TradeOrderStateMachineEnum.WAIT_FOR_DELIVER.getValue());
}
log.info("取消数量事件之后,订单的状态为:{}"+tradeOrder.getOrderState());
}
private boolean isAllAudit(TradeOrder tradeOrder) {
for (TradeOrderDetail tradeOrderDetail : tradeOrder.getTradeOrderDetailList()) {
if(ObjectUtils.isEmpty(tradeOrderDetail.getCancelQty())){
tradeOrderDetail.setCancelQty(0);
}
if(ObjectUtils.isEmpty(tradeOrderDetail.getAuditQty())){
tradeOrderDetail.setAuditQty(0);
}
//待评审的数量
if(tradeOrderDetail.getItemQty()-tradeOrderDetail.getCancelQty()-tradeOrderDetail.getAuditQty()!=0){
return false;
}
}
return true;
}
private boolean isAllDeliver(TradeOrder tradeOrder) {
for (TradeOrderDetail tradeOrderDetail : tradeOrder.getTradeOrderDetailList()) {
if(ObjectUtils.isEmpty(tradeOrderDetail.getCancelQty())){
tradeOrderDetail.setCancelQty(0);
}
if(ObjectUtils.isEmpty(tradeOrderDetail.getDeliverQty())){
tradeOrderDetail.setDeliverQty(0);
}
//待评审的数量
if(tradeOrderDetail.getItemQty()-tradeOrderDetail.getCancelQty()-tradeOrderDetail.getDeliverQty()!=0){
return false;
}
}
return true;
}
private boolean isAllSign(TradeOrder tradeOrder) {
for (TradeOrderDetail tradeOrderDetail : tradeOrder.getTradeOrderDetailList()) {
if(ObjectUtils.isEmpty(tradeOrderDetail.getCancelQty())){
tradeOrderDetail.setCancelQty(0);
}
if(ObjectUtils.isEmpty(tradeOrderDetail.getCustSignQty())){
tradeOrderDetail.setCustSignQty(0);
}
//代签收的数量
if((tradeOrderDetail.getItemQty()-tradeOrderDetail.getCancelQty()-tradeOrderDetail.getCustSignQty()!=0)){
return false;
}
}
return true;
}
}
TradeOrderAction
@WithStateMachine(id= TradeOrderStateMachineBuilder.MACHINEID_TO)
public class TradeOrderAction {
private static final String TRADE_ORDER = StateMachineHeaderNameConstants.TRADE_ORDER;
@OnTransition(source = "WAIT_FOR_PAY", target = "WAIT_FOR_AUDIT")
public void CUSTOMER_PAY(Message message) {
TradeOrder tradeOrder = (TradeOrder) message.getHeaders().get(TRADE_ORDER);
tradeOrder.setOrderState(TradeOrderStateMachineEnum.WAIT_FOR_AUDIT.getValue());
}
@OnTransition(source = "WAIT_FOR_PAY", target = "CLOSED")
public void CUSTOMER_CLOSE(Message message) {
TradeOrder tradeOrder = (TradeOrder) message.getHeaders().get(TRADE_ORDER);
tradeOrder.setOrderState(TradeOrderStateMachineEnum.CLOSED.getValue());
}
@OnTransition(source = "WAIT_FOR_AUDIT", target = "WAIT_FOR_DELIVER")
public void CUSTOMER_AUDIT(Message message) {
TradeOrder tradeOrder = (TradeOrder) message.getHeaders().get(TRADE_ORDER);
tradeOrder.setOrderState(TradeOrderStateMachineEnum.WAIT_FOR_DELIVER.getValue());
}
@OnTransition(source = "WAIT_FOR_DELIVER", target = "WAIT_FOR_SIGN")
public void CUSTOMER_DELIVER(Message message) {
TradeOrder tradeOrder = (TradeOrder) message.getHeaders().get(TRADE_ORDER);
tradeOrder.setOrderState(TradeOrderStateMachineEnum.WAIT_FOR_SIGN.getValue());
}
@OnTransition(source = "WAIT_FOR_EVALUATE", target = "COMPLETED")
public void CUSTOMER_EVALUATE(Message message) {
TradeOrder tradeOrder = (TradeOrder) message.getHeaders().get(TRADE_ORDER);
tradeOrder.setOrderState(TradeOrderStateMachineEnum.COMPLETED.getValue());
}
}
这个类是为了发message保证header一致,当然也可以硬编码保证一致。
StateMachineHeaderNameConstants
public class StateMachineHeaderNameConstants {
//交易订单
public static final String TRADE_ORDER = "tradeOrder";
}
StateMachineUtils
@Slf4j
public class StateMachineUtils {
private static final String TRADE_ORDER = StateMachineHeaderNameConstants.TRADE_ORDER;
@Autowired
private TradeOrderStateMachineBuilder tradeOrderStateMachineBuilder;
@Resource(name = "tradeOrderStateMachinePersister")
private StateMachinePersister tradeOrderStateMachinePersister;
public void execute(TradeOrder tradeOrder, TradeOrderEvent event) throws Exception{
log.debug("调用状态机前的订单状态为>>>>>>>>>>{}"+tradeOrder.getOrderState());
//获取TO状态机
StateMachine stateMachine = tradeOrderStateMachineBuilder.build();
Message message = MessageBuilder.withPayload(event).setHeader(TRADE_ORDER, tradeOrder).build();
//初始化状态机
tradeOrderStateMachinePersister.restore(stateMachine,tradeOrder);
stateMachine.sendEvent(message);
log.debug("调用状态机后的订单状态为>>>>>>>>>>{}"+tradeOrder.getOrderState());
}
}
这里说一下,为什么要用StateMachinePersister,这个主要作用是做持久化的,当然还有做redis持久化,我这边没用到就没写。而在这里引用是为了初始化状态机的状态,能让状态机一进来就是自己想要的状态的。不然触发不了流转规则。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VJjSM7rM-1631519370359)(D:\MyData\ligy112\AppData\Roaming\Typora\typora-user-images\image-20210913151753492.png)]
这里一定要记得配置对应的状态。
withChoice的生效,是又上一个withExternal流程后,如果直接设置withChoice里面的状态,是不能执行guard和action。所以我这边才会多出一个中间态,就是为了触发流转判断的。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IN3DCLWI-1631519370361)(D:\MyData\ligy112\AppData\Roaming\Typora\typora-user-images\image-20210913152331982.png)]
在一般情况下,我们都可以switch来判断,不用新建一堆guard类,但是在withChoice的first,then,lat里面的状态是流转后,但是不能用这个判断,自己可以打印下日志试下。这也是我为什么在GuardFactory里现有许多内部类的原因。
其实这个问题跟上一个问题有点像,用注解方式的话,一般都会有target,但是在withChoice里的target是上一个withExternal的target,所以是不会生效的。下图是一般情况的action配置注解。
@OnTransition(source = "WAIT_FOR_PAY", target = "WAIT_FOR_AUDIT")
所以这也是为什么会有两种方式的Action。
StateMachine还是挺好的,能够省掉很多ifelse,更重要是让业务解耦。当然以上是我个人实际开发遇到的问题,就想记录下来而已。有什么错误,请指出,毕竟我也是个菜鸟,这就当是我个人的笔记而已。