当前位置: 首页 > news >正文

松鼠状态机流转-@Transit

疑问

状态from to合法性校验,都是在代码中手动进行的吗,不是状态机自动进行的?

注解中from状态,代表当前状态

和谁校验:上下文中初始状态

怎么根据注解找到执行方法的

分析代码,创建运单,怎么关联到注解 @Transit(from = "unsigned", to = "unsigned", on = "CREATE"),的,怎么根据注解找到执行方法的?

package com.smcv.mall.tasks.statemachine;import com.alibaba.fastjson.JSON;
import com.smcv.mall.api.tasks.model.JghcTaskDTO.JghcTaskCreateForDP;
import com.smcv.mall.tasks.constant.ErrConstant;
import com.smcv.mall.tasks.ddd.domain.impl.TaskStatusTriggerService;
import com.smcv.mall.tasks.ddd.domain.inf.IDPStatusService;
import com.smcv.mall.tasks.exception.YlTaskException;
import com.smcv.mall.tasks.model.dto.DPTaskStatusChangeReqDTO;
import com.smcv.mall.tasks.statemachine.constant.DPEventEnum;
import com.smcv.mall.tasks.statemachine.constant.DPStateEnum;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.squirrelframework.foundation.fsm.annotation.StateMachineParameters;
import org.squirrelframework.foundation.fsm.annotation.Transit;
import org.squirrelframework.foundation.fsm.annotation.Transitions;
import org.squirrelframework.foundation.fsm.impl.AbstractUntypedStateMachine;/**
*/
@Transitions({
//创建运单
@Transit(from = "unsigned", to = "unsigned", on = "CREATE"),/*** 未指派 - 执行中* 1.扫码抢单* 2.派单员指派* 3.自提单*/@Transit(from = "unsigned", to = "executing", on = "ASSIGN_EXCUTING", callMethod = "assignExcuting"),/*** 已指派 - 执行中* 1.扫码抢单* 2.派单员指派*/@Transit(from = "signed", to = "executing", on = "ASSIGN_EXCUTING", callMethod = "assignExcuting"),/*** 未指派 - 已指派* 1.超时指派* 2.司机抢单*/@Transit(from = "unsigned", to = "signed", on = "ASSIGN_SIGNED"),//执行运单@Transit(from = "signed", to = "executing", on = "EXECUTING"),//前往途经点@Transit(from = "waitStart", to = "toStart", on = "CHILD_TOSTART", callMethod = "childTostart"),//前往途经点 兼容老版本@Transit(from = "contacted", to = "toStart", on = "CHILD_TOSTART", callMethod = "childTostart"),//到达途经点@Transit(from = "toStart", to = "toEnd", on = "CHILD_TOEND"),//待出发 - 到达途经点@Transit(from = "waitStart", to = "toEnd", on = "CHILD_WAITTOEND"),//前往下一个途经点@Transit(from = "toEnd", to = "toNextStart", on = "CHILD_TONEXTSTART", callMethod = "childTonextstart"),//前往下一个途经点  兼容老版本@Transit(from = "payed", to = "toNextStart", on = "CHILD_TONEXTSTART", callMethod = "childTonextstart"),//运单完成@Transit(from = "executing", to = "finished", on = "FINISH"),//运单取消@Transit(from = "unsigned", to = "canceled", on = "CANCEL", callMethod = "cancel"),@Transit(from = "signed", to = "canceled", on = "CANCEL", callMethod = "cancel"),@Transit(from = "executing", to = "canceled", on = "CANCEL", callMethod = "cancel"),@Transit(from = "canceled", to = "canceled", on = "CANCEL", callMethod = "cancel"),//幂等性
})
@StateMachineParameters(stateType = DPStateEnum.class, eventType = DPEventEnum.class, contextType = DPContext.class)
@Slf4j(topic = "task")
public class DPStateMachine extends AbstractUntypedStateMachine {private static final String LOG_PRE = "【{}】地跑状态流转,orderNumber=[{}],fromState=[{}],toState=[{}],event=[{}],context=[{}]";protected ApplicationContext applicationContext;private IDPStatusService idpStatusService;/*** 初始化时候会调用,类似后置处理器** @param applicationContext*/
public void postConstruct(ApplicationContext applicationContext) {this.applicationContext = applicationContext;
}/*** 开始执行之前的方法** @param fromState* @param event* @param context*/
@Override
protected void beforeTransitionBegin(Object fromState, Object event, Object context) {log.info(LOG_PRE, Thread.currentThread().getStackTrace()[1].getMethodName(), ((DPContext) context).getOrderNumber(), fromState, null, event, context);//获取状态机服务类idpStatusService = (IDPStatusService) ((DPContext) context).getIStatusService();
}/*** 事件触发之前被调用** @param fromState* @param toState* @param event* @param context*/
@Override
protected void beforeActionInvoked(Object fromState, Object toState, Object event, Object context) {log.info(LOG_PRE, Thread.currentThread().getStackTrace()[1].getMethodName(), ((DPContext) context).getOrderNumber(), fromState, toState, event, context);/*** 状态合理性校验*/DPContext dpContext = (DPContext) context;if (!dpContext.isReentrantLock()) {//重入锁,不需要状态合理性校验DPEventEnum dpEventEnum = (DPEventEnum) event;((TaskStatusTriggerService) dpContext.getIStatusService()).checkFromState(fromState, toState, context, dpEventEnum);}
}/*** 非法状态流转** @param fromState* @param event* @param context*/
@Override
protected void afterTransitionDeclined(Object fromState, Object event, Object context) {log.info(LOG_PRE, Thread.currentThread().getStackTrace()[1].getMethodName(), ((DPContext) context).getOrderNumber(), fromState, null, event, context);throw new YlTaskException(ErrConstant.BUSI_RETURN_ERR, "状态流转异常");
}/*** 正常执行完毕后执行的方法** @param fromState* @param toState* @param event* @param context*/
@Override
protected void afterTransitionCompleted(Object fromState, Object toState, Object event, Object context) {log.info(LOG_PRE, Thread.currentThread().getStackTrace()[1].getMethodName(), ((DPContext) context).getOrderNumber(), fromState, toState, event, context);
}/*** 执行异常** @param fromState* @param toState* @param event* @param context*/
@SneakyThrows
@Override
protected void afterTransitionCausedException(Object fromState, Object toState, Object event, Object context) {log.info(LOG_PRE, Thread.currentThread().getStackTrace()[1].getMethodName(), ((DPContext) context).getOrderNumber(), fromState, toState, event, context);//此处不调用父类方法,异常不会被抛出//super.afterTransitionCausedException(fromState, toState, event, context);if (getLastException().getTargetException() != null) {//重写父类方法,向外抛出自定义异常throw getLastException().getTargetException();} else {super.afterTransitionCausedException(fromState, toState, event, context);}
}/*** 状态机执行完毕必须执行的方法,不管成功/失败与否** @param fromState* @param toState* @param event* @param context*/
@Override
protected void afterTransitionEnd(Object fromState, Object toState, Object event, Object context) {log.info(LOG_PRE, Thread.currentThread().getStackTrace()[1].getMethodName(), ((DPContext) context).getOrderNumber(), fromState, toState, event, context);super.afterTransitionEnd(fromState, toState, event, context);
}/*** 创建运单** @param fromState* @param toState* @param dpEventEnum* @param dpContext*/
public void transitFromunsignedTounsignedOnCREATE(DPStateEnum fromState, DPStateEnum toState, DPEventEnum dpEventEnum, DPContext dpContext) {log.info(LOG_PRE, Thread.currentThread().getStackTrace()[1].getMethodName(), dpContext.getOrderNumber(), fromState, toState, dpEventEnum, dpContext);JghcTaskCreateForDP jghcTaskCreateForDP = dpContext.getJghcTaskCreateForDP();jghcTaskCreateForDP.setServiceCode(dpContext.getCreateChannel());idpStatusService.createTask(jghcTaskCreateForDP);
}/*** 指派运单[状态流转到执行中]** @param fromState* @param toState* @param dpEventEnum* @param dpContext*/
public void assignExcuting(DPStateEnum fromState, DPStateEnum toState, DPEventEnum dpEventEnum, DPContext dpContext) {log.info(LOG_PRE, Thread.currentThread().getStackTrace()[1].getMethodName(), dpContext.getOrderNumber(), fromState, toState, dpEventEnum, dpContext);DPTaskStatusChangeReqDTO dpTaskStatusChangeReqDTO = dpContext.getDpTaskStatusChangeReqDTO();dpTaskStatusChangeReqDTO.setFromState(fromState);dpTaskStatusChangeReqDTO.setToState(toState);idpStatusService.assignExcuting(dpTaskStatusChangeReqDTO);
}/*** 指派运单[状态流转到已指派]** @param fromState* @param toState* @param dpEventEnum* @param dpContext*/
public void transitFromunsignedTosignedOnASSIGN_SIGNED(DPStateEnum fromState, DPStateEnum toState, DPEventEnum dpEventEnum, DPContext dpContext) {log.info(LOG_PRE, Thread.currentThread().getStackTrace()[1].getMethodName(), dpContext.getOrderNumber(), fromState, toState, dpEventEnum, dpContext);DPTaskStatusChangeReqDTO dpTaskStatusChangeReqDTO = dpContext.getDpTaskStatusChangeReqDTO();dpTaskStatusChangeReqDTO.setFromState(fromState);dpTaskStatusChangeReqDTO.setToState(toState);idpStatusService.assignSigned(dpTaskStatusChangeReqDTO);
}/*** 执行运单** @param fromState* @param toState* @param dpEventEnum* @param dpContext*/
public void transitFromsignedToexecutingOnEXECUTING(DPStateEnum fromState, DPStateEnum toState, DPEventEnum dpEventEnum, DPContext dpContext) {log.info(LOG_PRE, Thread.currentThread().getStackTrace()[1].getMethodName(), dpContext.getOrderNumber(), fromState, toState, dpEventEnum, dpContext);DPTaskStatusChangeReqDTO dpTaskStatusChangeReqDTO = dpContext.getDpTaskStatusChangeReqDTO();dpTaskStatusChangeReqDTO.setFromState(fromState);dpTaskStatusChangeReqDTO.setToState(toState);
//        dpContext.setDpTaskStatusChan

在给定的代码中,状态机的行为是通过 @Transit 注解定义的,这些注解指明了状态转移的规则和事件,并且关联了执行的方法。具体来说,@Transit 注解配置了状态从 fromto 的转移条件,以及触发该状态转移的事件 (on)。有些 @Transit 注解还指定了 callMethod 属性,表示当该转移发生时,应该调用哪个方法来执行相关逻辑。

注解分析

 

java

@Transit(from = "unsigned", to = "unsigned", on = "CREATE")

这个注解表示当事件 CREATE 发生时,状态从 unsigned 转移到 unsigned。这是一种状态机的事件与状态的定义。

方法执行关联

  1. 方法名与注解中的 callMethod 对应: 在注解中,可以通过 callMethod 属性指定状态转换时需要调用的方法。如果 callMethod 被指定,状态机在状态转换时会执行这个方法。例如:

     

    java

    @Transit(from = "unsigned", to = "executing", on = "ASSIGN_EXCUTING", callMethod = "assignExcuting")

    这个注解表示当事件 ASSIGN_EXCUTING 发生时,状态从 unsigned 转移到 executing,并且会调用 assignExcuting 方法。

  2. 方法调用的方式: 对于状态机中的状态转换,当事件触发时,注解框架(在这个例子中是 Squirrel 状态机库)会通过反射查找并调用注解中指定的 callMethod 方法。具体来说,框架会使用事件、状态和上下文信息来找到正确的方法并执行。

  3. 如何根据注解找到执行方法

    • 在代码执行的过程中,当事件发生并触发状态机的状态转换时,状态机框架会检查该状态转换是否带有 callMethod
    • 如果 callMethod 指定了方法名,框架会使用反射机制去查找与该方法名匹配的实例方法,并调用它。
    • 例如,当 on = "CREATE" 事件发生时,如果没有指定 callMethod,那么该状态转移会自动被处理(状态变化本身不需要调用方法)。但如果 callMethod 被指定,状态转移发生时就会调用指定的方法(如 transitFromunsignedTounsignedOnCREATE 方法)。
  4. 如何定义方法

    • 每个方法签名都应该与状态机的定义保持一致,即方法应该接受 fromStatetoStateeventcontext 等参数。
    • 例如,在 transitFromunsignedTounsignedOnCREATE 方法中,签名是:
       

      java

      public void transitFromunsignedTounsignedOnCREATE(DPStateEnum fromState, DPStateEnum toState, DPEventEnum dpEventEnum, DPContext dpContext) 这个方法的作用是处理从 unsigned 到 unsigned 状态的转换,并且根据 CREATE 事件的触发执行特定的操作。其实现逻辑可以是创建运单等操作。

事件触发与方法调用的流程

  1. 触发事件:当事件(如 CREATE)被触发时,状态机会根据状态机的配置来查找与该事件相关的状态转移。
  2. 查找对应的 @Transit 注解:框架会检查所有的 @Transit 注解,找出符合当前事件的注解。例如,如果当前事件是 CREATE,它会检查所有定义了 on = "CREATE" 的注解。
  3. 调用指定的方法:如果某个 @Transit 注解指定了 callMethod 属性(如 transitFromunsignedTounsignedOnCREATE),框架会使用反射来调用相应的方法。

例如,下面这个注解:

 

java

@Transit(from = "unsigned", to = "unsigned", on = "CREATE")

CREATE 事件发生时,框架会寻找与该事件相关的状态转移逻辑。如果没有指定 callMethod,则仅处理状态转移。如果有指定方法(如 transitFromunsignedTounsignedOnCREATE),它会调用该方法来处理相关逻辑。

总结

  • 注解中的 @Transit 定义了事件与状态的转移规则。
  • callMethod 属性允许开发者为状态转移指定自定义的处理方法。
  • 状态机框架使用反射来根据注解动态调用对应的方法。
  • callMethod 指定的方法需要具备一定的签名(通常包括 fromStatetoStateevent 和 context)。

通过这种方式,状态机可以动态地根据事件和状态转移配置,执行预定的操作。

如果直接根据事件on,callMethod 找到对应的方法,状态from to,有什么用

你提到的问题是关于 状态机@Transit 注解中的 fromto 参数,如果在事件处理时,已经通过 oncallMethod 找到对应的方法,那么 fromto 的作用是什么?这两个参数的意义其实是非常重要的,下面我会逐一解释它们在状态机中的作用。

1. 状态 (from 和 to) 用于验证状态转换

尽管 callMethod 指定了方法来执行特定的逻辑,但是 fromto 这两个参数仍然有它们的关键作用,尤其是在 验证和控制状态流转的合法性 方面。

主要作用:
  • 状态的合法性检查from 和 to 定义了状态机中状态的合法转换路径。它们确保了事件不会导致非法的状态跳跃,保证了状态流转的一致性。
  • 保障状态流转的一致性:通过定义明确的状态流转路径(从 from 到 to),状态机可以防止不符合逻辑的状态转移。例如,如果状态机中定义了只能从 "未指派" (unsigned) 到 "已指派" (signed) 的状态流转,那么如果你尝试从 "执行中" (executing) 到 "已指派" (signed) 的转移,状态机应该阻止该转移。
示例:
 

java

@Transit(from = "unsigned", to = "signed", on = "ASSIGN_SIGNED")

这里,from = "unsigned"to = "signed" 表示只有在状态是 unsigned 时,事件 ASSIGN_SIGNED 才能触发状态从 unsignedsigned 的转移。如果状态已经是 signed,即使事件 ASSIGN_SIGNED 被触发,状态机会拒绝该转移。

2. 事件的路由控制

在复杂的状态机中,可能存在多个事件和方法都可以引发相似的状态转换。例如,你可能有多个事件(如 ASSIGN_EXCUTING)可以从不同的源状态(如 unsignedsigned)转换到同一个目标状态(如 executing)。在这种情况下,fromto 就起到了关键作用,它们有助于确保事件在正确的上下文中被触发,并确保事件与状态之间的关系是明确的。

例如:
 

java

@Transit(from = "unsigned", to = "executing", on = "ASSIGN_EXCUTING", callMethod = "assignExcuting") @Transit(from = "signed", to = "executing", on = "ASSIGN_EXCUTING", callMethod = "assignExcuting")

这两个注解表明,ASSIGN_EXCUTING 事件可以发生在两种不同的源状态 (unsignedsigned) 下,转移到相同的目标状态 (executing)。但是,实际的状态流转只有在这些源状态下才会发生。因此,fromto 参数确保了事件和状态之间的明确关系。

3. 帮助调试和日志记录

fromto 的状态信息在调试和日志记录中也非常有用。在实际的运行时,日志会记录状态机的状态流转,包括当前的源状态 (fromState) 和目标状态 (toState),这些信息帮助开发者了解状态机的运行轨迹。

例如,在方法中,通常会记录每个状态转换的日志:

 

java

log.info("Transitioning from {} to {} via event {}. Context: {}", fromState, toState, event, context);

这种日志信息有助于在问题出现时快速定位问题并排查逻辑错误。

4. 确保不同的状态转换逻辑

fromto 不仅帮助确定状态转移是否合法,还能在不同的状态之间实现不同的逻辑。例如,你可能希望根据当前状态 (fromState) 的不同执行不同的操作或方法。虽然 callMethod 指定了通用的执行方法,但你仍然可能希望根据不同的状态执行不同的逻辑。

例如:

 

java

@Transit(from = "unsigned", to = "signed", on = "ASSIGN_SIGNED", callMethod = "assignUnsignedToSigned") @Transit(from = "signed", to = "executing", on = "ASSIGN_EXCUTING", callMethod = "assignSignedToExecuting")

在这个例子中,尽管事件 ASSIGN_SIGNEDASSIGN_EXCUTING 看起来可能是类似的动作,但它们发生在不同的状态下,因此你可能会希望它们触发不同的处理逻辑。fromto 的定义确保了在正确的上下文中执行正确的逻辑。

5. 保持代码清晰和可维护

fromto 提供了清晰的状态流转图,开发者可以从注解中快速了解状态机的行为和状态转换路径。这对于团队协作、文档编写以及代码的长期维护都非常有帮助。

总结

尽管 callMethod 可以直接指定要调用的方法,但是 fromto 参数在状态机中扮演着不可或缺的角色:

  • 状态合法性验证:确保状态流转是符合预定义的规则的,避免出现不符合逻辑的状态跳跃。
  • 路由控制:帮助事件在正确的上下文中触发,从正确的源状态转换到目标状态。
  • 调试与日志记录:提供调试信息,帮助开发者追踪状态转移的路径。
  • 不同状态的逻辑控制:根据 from 和 to 确定具体的业务逻辑。

因此,fromto 并非多余,它们在状态机的结构化和规则验证中发挥了重要作用,确保状态转移的过程是可控和符合业务逻辑的。

具体如何状态合法性验证

状态合法性验证:确保状态流转是符合预定义的规则的,避免出现不符合逻辑的状态跳跃。 这个具体如何实现的?from代表当前状态?这个参数怎么传入的

在状态机的实现中,状态合法性验证是确保状态转移符合预定义的规则、避免非法的状态跳跃的关键。具体来说,from 代表当前的状态,to 代表目标状态,验证这两个状态的合法转移可以通过一系列的机制来实现。

1. from 代表当前状态,to 代表目标状态

  • from:表示当前的状态,即事件触发时所处的状态。
  • to:表示目标状态,即状态转换后将进入的状态。

状态合法性验证的核心任务就是在事件发生时,检查当前状态(from)和目标状态(to)是否符合预定义的合法转换规则。如果不合法,状态机应该拒绝该转换并抛出异常或返回错误。

2. 如何实现状态合法性验证?

实现状态合法性验证的方式可以分为几种,不同的状态机框架或自定义实现可能会有不同的方法。以下是常见的几种实现方式:

2.1. 手动映射与检查

一种最简单的实现方式是手动维护一个合法的状态转换表,在处理事件时检查当前状态和目标状态是否允许转换。

例如:

  • 使用一个状态转换表来存储所有合法的 from -> to 映射。
  • 当事件发生时,根据当前状态(from)和目标状态(to)查表,检查转换是否合法。

假设我们有如下状态和状态转换表:

 

java

enum State { UNSIGNED, SIGNED, EXECUTING, COMPLETED } Map<State, Set<State>> validTransitions = new HashMap<>(); validTransitions.put(State.UNSIGNED, new HashSet<>(Arrays.asList(State.SIGNED))); validTransitions.put(State.SIGNED, new HashSet<>(Arrays.asList(State.EXECUTING))); validTransitions.put(State.EXECUTING, new HashSet<>(Arrays.asList(State.COMPLETED)));

当事件触发时,我们可以检查状态是否合法:

 

java

public boolean isValidTransition(State fromState, State toState) { Set<State> validToStates = validTransitions.get(fromState); return validToStates != null && validToStates.contains(toState); }

在状态转移时,isValidTransition 方法就会验证 fromto 是否匹配预定义的合法转换。

2.2. 通过注解与反射动态绑定

在使用注解驱动的状态机框架中,状态转移规则通常通过注解(如 @Transit)来定义。状态机会通过反射机制读取这些注解,并验证事件发生时的状态转移是否合法。

例如,在基于注解的状态机实现中,可能会有如下的代码:

 

java

@Transit(from = "UNSIGNED", to = "SIGNED", on = "ASSIGN_SIGNED") @Transit(from = "SIGNED", to = "EXECUTING", on = "ASSIGN_EXECUTING")

在处理事件时,框架会根据注解定义的 fromto 来验证当前状态和目标状态是否匹配。可以通过以下方式实现:

  1. 读取注解:通过反射获取方法上的注解,提取出 from 和 to 状态。
  2. 检查合法性:比对当前状态与目标状态是否符合注解中定义的合法状态流转。

假设我们有一个 StateMachine 类,在事件发生时,我们通过反射查找匹配的转移规则:

 

java

public void handleEvent(String event, State currentState) throws IllegalStateException { // 获取所有标注了 @Transit 注解的方法 Method[] methods = StateMachine.class.getDeclaredMethods(); for (Method method : methods) { if (method.isAnnotationPresent(Transit.class)) { Transit transit = method.getAnnotation(Transit.class); if (transit.from().equals(currentState.name()) && transit.on().equals(event)) { // 验证目标状态是否合法 if (validTransitions(currentState, transit.to())) { // 执行状态转换方法 method.invoke(this); } else { throw new IllegalStateException("Invalid state transition from " + currentState + " to " + transit.to()); } } } } }

在这种方式下,fromto 都是通过注解定义的,在事件处理时,框架会动态检查当前状态和目标状态是否符合合法转移规则。

2.3. 状态机框架中的自动检查

一些状态机框架(如 Spring State MachineAkka FSM 等)已经内建了状态转移规则的验证机制。它们通过状态机的图结构自动验证 fromto 之间的合法性,开发者只需要通过配置或者注解来定义状态转移,而框架会在运行时执行验证。

例如,Spring State Machine 提供了一些 API 来配置状态转换:

 

java

StateMachine<State, Event> stateMachine = new StateMachineBuilder.Builder<State, Event>() .configure() .withStates() .initial(State.UNSIGNED) .state(State.SIGNED) .state(State.EXECUTING) .state(State.COMPLETED) .and() .withTransitions() .between(State.UNSIGNED, State.SIGNED).perform(assignSigned()) .between(State.SIGNED, State.EXECUTING).perform(assignExecuting()) .between(State.EXECUTING, State.COMPLETED).perform(assignCompleted()) .and() .build();

在这里,框架会在 StateMachine 被激活后自动检查每个状态转移是否合法。

3. from 参数如何传入

from 代表当前状态,它通常是从当前的 状态机实例 中获取的。具体来说:

  • 如果状态机是基于事件驱动的,那么 from 状态通常是触发事件时状态机当前的状态。
  • 在基于注解的状态机中,from 状态会在处理事件时动态传入。
  • 在手动配置的状态机中,from 状态会随着事件的触发而改变,通常由当前的 state 属性表示。

例如,在事件处理方法中,from 通常是方法的参数或者是类中的实例变量:

 

java

public void handleEvent(State currentState, Event event) { // 当前状态:currentState if (isValidTransition(currentState, event)) { // 执行状态转移 } }

在注解驱动的框架中,from 可能会自动由框架通过反射从注解中获取,或者从事件的上下文中获取当前状态。

4. 总结

状态合法性验证的关键是在事件触发时检查当前状态(from)和目标状态(to)是否符合预定义的合法转换规则。具体实现可以通过手动维护转换表、反射检查注解或使用状态机框架的自动验证来实现。通过这些方法,我们能够确保状态机的状态流转始终是符合业务逻辑的,并避免发生不符合规则的状态跳跃。

状态合法性校验实现例子

触发点,方法执行前

    /*** 事件触发之前被调用** @param fromState* @param toState* @param event* @param context*/@Overrideprotected void beforeActionInvoked(Object fromState, Object toState, Object event, Object context) {log.info(LOG_PRE, Thread.currentThread().getStackTrace()[1].getMethodName(), ((DPContext) context).getOrderNumber(), fromState, toState, event, context);/*** 状态合理性校验*/DPContext dpContext = (DPContext) context;if (!dpContext.isReentrantLock()) {//重入锁,不需要状态合理性校验DPEventEnum dpEventEnum = (DPEventEnum) event;((TaskStatusTriggerService) dpContext.getIStatusService()).checkFromState(fromState, toState, context, dpEventEnum);}}
    public void checkFromState(DPStateEnum dpStateEnum_from, DPStateEnum dpStateEnum_to, DPContext dpContext, DPEventEnum eventEnum) {
// from statusgetInitialState(dpContext.getEvent(), Optional.ofNullable(dpContext.getDpTaskStatusChangeReqDTO()).map(dpTaskStatusChangeReqDTO -> dpTaskStatusChangeReqDTO.getWayBill()).orElse(""), dpContext);if (!dpContext.getInitialState().equals(dpStateEnum_from)) {log.error("状态异常");throw new YlTaskException(ErrConstant.BUSI_RETURN_ERR, "状态异常");}// to status//幂等性处理if (Arrays.asList(DPEventEnum.CANCEL).contains(eventEnum)) {String taskStatus_db = ttTask.getTaskStatus();if (taskStatus_db.equals(dpStateEnum_to.getStatusCode())) {log.warn("当前运单已处理");dpContext.setIdempotent(true);return;}}}

http://www.lryc.cn/news/516094.html

相关文章:

  • 微信小程序调用 WebAssembly 烹饪指南
  • # LeetCode Problem 2038: 如果相邻两个颜色均相同则删除当前颜色 (Winner of the Game)
  • Redis面试相关
  • 4.CSS文本属性
  • Mongo高可用架构解决方案
  • Rabbitmq 业务异常与未手动确认场景及解决方案
  • linux,centos7.6安装禅道
  • java基础之代理
  • 计算机网络——期末复习(6)期末考试样例2(含答案)
  • JavaScript 获取DOM对象
  • 一文讲明白朴素贝叶斯算法及其计算公式(入门普及)
  • 实际开发中,常见pdf|word|excel等文件的预览和下载
  • Python自学 - 递归函数
  • Spark-Streaming有状态计算
  • Markdown如何导出Html文件Markdown文件
  • 使用Python进行图像裁剪和直方图分析
  • 企业内管信息化系统
  • 【python因果库实战15】因果生存分析4
  • Linux 线程详解
  • 云架构:考量与框架
  • SD下载、安装、使用、卸载-Stable Diffusion整合包v4.10发布!
  • java 发送邮件
  • 聚类系列 (二)——HDBSCAN算法详解
  • AngularJS HTML DOM
  • C语言延时实现
  • OSI模型的网络层中产生拥塞的主要原因?
  • 机器学习周报-ModernTCN文献阅读
  • 什么是网关路由
  • 信号的产生、处理
  • 在Linux中,zabbix如何监控脑裂?