Spring StateMachine狀態(tài)機(jī)引擎在項(xiàng)目中的應(yīng)用(四)-流程配置

狀態(tài)機(jī)配置

狀態(tài)機(jī)配置有兩種方式,

  • 創(chuàng)建config類(lèi),實(shí)現(xiàn)StateMachineConfigurer(或者根據(jù)S\E的不同,直接繼承其子類(lèi)StateMachineConfigurerAdapter、EnumStateMachineConfigurerAdapter),然后分別重寫(xiě)其不同的configure方法,用于指定對(duì)應(yīng)配置。
  • 依然實(shí)現(xiàn)StateMachineConfigurer(或繼承其子類(lèi)),不過(guò)通過(guò)StateMachineBuilder.<States, Events>builder()來(lái)指定對(duì)應(yīng)配置。

我更傾向于用第二種方式,可以自定義不同的builder,以服務(wù)于不同的業(yè)務(wù)場(chǎng)景,通過(guò)顯式指定那個(gè)builder的方式來(lái)選擇對(duì)應(yīng)的業(yè)務(wù)狀態(tài)機(jī)配置。

自定義接口

自定義了一個(gè)Builder接口,用于規(guī)范定義不同業(yè)務(wù)的狀態(tài)機(jī)配置。

import org.springframework.beans.factory.BeanFactory;
import org.springframework.statemachine.StateMachine;

/**
 * 狀態(tài)機(jī)構(gòu)造器定義
 */
public interface BizOrderStateMachineBuilder {

    String getName();

    StateMachine<BizOrderStatusEnum, BizOrderStatusChangeEventEnum> build(BeanFactory beanFactory) throws Exception;

    // 業(yè)務(wù)一對(duì)應(yīng)的builder name
    String WYLOAN_BUILDER_NAME = "wyLoanStateMachineBuilder";

    // 業(yè)務(wù)二對(duì)應(yīng)的builder name
    String VPAY_BUILDER_NAME = "vpayStateMachineBuilder";
}

對(duì)應(yīng)的設(shè)置業(yè)務(wù)狀態(tài)機(jī)配置Builder,注意這里不需要@EnableStateMachine注解,不是springboot環(huán)境:

@Component
@Slf4j
public class WYLoanBizOrderStateMachineBuilder extends EnumStateMachineConfigurerAdapter implements BizOrderStateMachineBuilder {

......

   @Override
    public String getName() {
        return WYLOAN_BUILDER_NAME;
    }

    @Override
    public StateMachine<BizOrderStatusEnum, BizOrderStatusChangeEventEnum> build(BeanFactory beanFactory) throws Exception {

        StateMachineBuilder.Builder<BizOrderStatusEnum, BizOrderStatusChangeEventEnum> builder = StateMachineBuilder.builder();

        builder.configureConfiguration()
                .withConfiguration()
                .autoStartup(true)
                .beanFactory(beanFactory)
                .machineId("WYLoanStateMachineId");

        // 初始化狀態(tài)機(jī),并指定狀態(tài)集合
        // 詳細(xì)說(shuō)明下,由于XXX將用戶實(shí)名+申請(qǐng)額度的流程都統(tǒng)一承載在訂單維度,所以這里有個(gè)分支流程處理相關(guān)數(shù)據(jù)
        // 包括實(shí)名、業(yè)務(wù)審核、資料補(bǔ)全、證件上傳、貸前額度審核等節(jié)點(diǎn)
        // 這塊流程與訂單流程全都耦合在一起,拆出來(lái)工作量及代價(jià)都比較大,所以在訂單系統(tǒng)中統(tǒng)一維護(hù)起來(lái)
        // 故XXX的業(yè)務(wù)狀態(tài)最多,也最復(fù)雜
        builder.configureStates()
                .withStates()
                .initial(CREATE)
                .choice(WYD_INITIAL_JUMP)
                .choice(CHECK_COMPLEMENT)
                .choice(CHECK_UPLOAD)
                .choice(IN_DEAL_RISK_AUDITING)
                .choice(REPAYING) // 還款ing 對(duì)應(yīng)的不同結(jié)果

                .end(CANCEL)
                .end(CLOSE)
                .end(SUCCESS)
                .states(EnumSet.allOf(BizOrderStatusEnum.class)) // 所有狀態(tài),避免有遺漏
        ;

        // 指定狀態(tài)機(jī)有哪些節(jié)點(diǎn),即遷移動(dòng)作
        builder.configureTransitions()
                // XXX的創(chuàng)建,并不是CREATE狀態(tài),而是為待實(shí)名WAIT_REAL_NAME_AUTH或者待借款WAIT_BORROW狀態(tài),
                // 所以需要虛擬節(jié)點(diǎn),自己跳轉(zhuǎn)
                .withExternal()
                .source(CREATE)
                .target(WYD_INITIAL_JUMP)
                .event(BizOrderStatusChangeEventEnum.EVT_CREATE)
                .action(orderCreateAction, errorHandlerAction)

                .and()
                .withChoice()
                .source(WYD_INITIAL_JUMP)
                .first(WAIT_REAL_NAME_AUTH, needNameAuthGurad(), needNameAuthAction)
                .then(WAIT_BORROW, toWaitBorrowGuard(), waitBorrowAction)
                .last(CREATE)

                /** 待實(shí)名WAIT_REAL_NAME_AUTH 可以到達(dá)的節(jié)點(diǎn) **/
                // cancel
                .and().withExternal()
                .source(WAIT_REAL_NAME_AUTH)
                .target(CANCEL)
                .event(EVT_CANCEL)
                .action(cancelAction, errorHandlerAction)

                // close
                .and().withExternal()
                .source(WAIT_REAL_NAME_AUTH)
                .target(CLOSE)
                .event(EVT_SYS_CLOSE)
                .action(closeAction, errorHandlerAction)

                // 實(shí)名,下一步是待hr審核
                .and().withExternal()
                .source(WAIT_REAL_NAME_AUTH)
                .target(WAIT_BIZ_AUDIT)
                .event(EVT_NAME_AUTH)
                .action(nameAuthAction, errorHandlerAction)

                /** 待BIZ審核可到達(dá)的節(jié)點(diǎn) **/
                // 關(guān)閉
                .and().withExternal()
                .source(WAIT_BIZ_AUDIT)
                .target(CLOSE)
                .event(EVT_REFUSE).guard(toCloseGuard())
                .action(closeAction, errorHandlerAction)

                // BIZ審核通過(guò),到待補(bǔ)全資料
                .and().withExternal()
                .source(WAIT_BIZ_AUDIT)
                .target(WAIT_COMPLEMENT)
                .event(EVT_AUDIT)
                .action(hrAuditAction, errorHandlerAction)

                /** 補(bǔ)全資料可以到達(dá)的節(jié)點(diǎn) **/
                // 待上傳證件
                .and().withExternal()
                .source(WAIT_COMPLEMENT)
                .target(CHECK_COMPLEMENT)
                .event(EVT_COMPLEMENT)

                // choice
                .and().withChoice()
                .source(CHECK_COMPLEMENT)
                .first(WAIT_COMPLEMENT, retryCompleteGuard(), retryCompleteAction)
                .last(WAIT_UPLOAD_IMG, completeAction)

                /** 上傳證件可以到達(dá)的節(jié)點(diǎn) **/
                .and().withExternal()
                .source(WAIT_UPLOAD_IMG)
                .target(CHECK_UPLOAD)
                .event(EVT_UPLOAD_IMG)

                .and().withChoice()
                .source(CHECK_UPLOAD)
                .first(WAIT_UPLOAD_IMG, retryUploadGuard(), retryUploadAction)
                .last(WAIT_BEF_DEAL_RISK_AUDIT, uploadAction)

                /** 貸前審核可以到達(dá)的節(jié)點(diǎn) **/
                // 關(guān)單
                .and().withExternal()
                .source(WAIT_BEF_DEAL_RISK_AUDIT)
                .target(CLOSE)
                .event(EVT_AUDIT)
                .guard(toCloseGuard())
                .action(closeAction, errorHandlerAction)

                // 跳轉(zhuǎn)到待借款
                .and().withExternal()
                .source(WAIT_BEF_DEAL_RISK_AUDIT)
                .target(WAIT_BORROW)
                .event(EVT_AUDIT)
                .guard(toWaitBorrowGuard())
                .action(befDealRiskAction, errorHandlerAction)


                /** 待借款可以到達(dá)的節(jié)點(diǎn) **/
                // 簽約環(huán)節(jié)補(bǔ)充所有待完善數(shù)據(jù),所以是從createService中發(fā)起此流程
                .and().withExternal()
                .source(WAIT_BORROW)
                .target(SIGNED)
                .event(EVT_SIGN)
                .action(signAction, errorHandlerAction)

                .and().withExternal()
                .source(WAIT_BORROW)
                .target(IN_DEAL_RISK_AUDITING)
                .event(EVT_AUDIT)

                .and().withChoice()
                .source(IN_DEAL_RISK_AUDITING)
                .first(CLOSE, toCloseGuard(), closeAction)
                .last(WAIT_SIGN, toWaitSignAction)

                .and().withExternal()
                .source(WAIT_SIGN)
                .target(SIGNED)
                .event(EVT_SIGN)
                .action(signAction, errorHandlerAction)// -- to be complete

                /** 簽約可以到達(dá)的節(jié)點(diǎn) **/
                .and().withExternal()
                .source(SIGNED)
                .target(LOANING)
                .event(EVT_LOAN)
                .action(loanAction, errorHandlerAction)

                /* 需要外部觸發(fā),暫時(shí)不用choice了,無(wú)法自己內(nèi)部決定
                .and().withChoice()
                .source(LOANING)
                .first(CLOSE, loanFailGuard(), closeAction)
                .last(LOANED, loanSuccGuard(), loanAction())*/
                .and().withExternal()
                .source(LOANING)
                .target(CLOSE)
                .event(EVT_LOAN_FAILED)
                .action(closeAction, errorHandlerAction)

                .and().withExternal()
                .source(LOANING)
                .target(LOANED)
                .event(EVT_LOAN_SUCC)
                .action(loanSuccAction, errorHandlerAction)


                /** 放款成功可以到達(dá)的節(jié)點(diǎn) **/
                .and().withExternal()
                .source(LOANED)
                .target(BILL_GEN)
                .event(EVT_GEN_BILL)
                .action(genBillAction, errorHandlerAction)

                /** 生成賬單 到逾期/還款 **/
                .and().withExternal()
                .source(BILL_GEN)
                .target(OVERDUE)
                .event(EVT_OVERDUE)
                .action(overdueAction, errorHandlerAction)

                .and().withExternal()
                .source(BILL_GEN)
                .target(REPAYING)
                .event(EVT_REPAY)

                // OVERDUE可以到達(dá)的節(jié)點(diǎn)
                .and().withExternal()
                .source(OVERDUE)
                .target(REPAYING)
                .event(EVT_REPAY)

                .and().withExternal()
                .source(PART_REPAID)
                .target(OVERDUE)
                .event(EVT_OVERDUE)
                .action(overdueAction, errorHandlerAction)

                .and().withExternal()
                .source(PART_REPAID)
                .target(REPAYING)
                .event(EVT_REPAY)

                // 還款過(guò)程,repaying可以到達(dá)的節(jié)點(diǎn)
                .and().withChoice()
                .source(REPAYING)
                .first(PART_REPAID, partRepayGuard(), partRepayAction) // 部分還款,到本身,狀態(tài)不變
                .last(REPAID, repaidAction) // 全部還款

                // repayed 可以到達(dá)的節(jié)點(diǎn)-success 銷(xiāo)賬
                .and().withExternal()
                .source(REPAID)
                .target(SUCCESS)
                .event(EVT_TOSUCCESS)
                .action(successAction, errorHandlerAction)
        ;


        return builder.build();
    }

......

}

這里先忽略對(duì)應(yīng)的guard及action,主要關(guān)注每個(gè)節(jié)點(diǎn)的配置(withXX\source\target\event),對(duì)照上文中的狀態(tài)變遷圖,理解這套配置。

創(chuàng)建狀態(tài)機(jī)引擎的工廠

這里封裝了調(diào)用builder生成對(duì)應(yīng)狀態(tài)機(jī)的實(shí)現(xiàn),如下所示

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.statemachine.StateMachine;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.vipfins.finance.middleplatform.order.statemachine.BizOrderStateMachineBuilder.WYLOAN_BUILDER_NAME;

@Component
public class BizOrderStateMachineBuildFactory implements InitializingBean {

    @Autowired
    private List<BizOrderStateMachineBuilder> builders;

    @Autowired
    private BeanFactory beanFactory;

    /**
     * 用來(lái)存儲(chǔ)builder-name及builder的map
     */
    private Map<String, BizOrderStateMachineBuilder> builderMap = Maps.newConcurrentMap();

    /**
     * 用于存儲(chǔ)bizType+subBizType 與 builder-name的集合
     */
    private Map<String, String> bizTypeBuilderMap = Maps.newConcurrentMap();


    /**
     * State machine instantiation is a relatively expensive operation so it is better to try to pool instances
     * instead of instantiating a new instance with every request
     * <p>
     * 不過(guò)目前先繼續(xù)每次請(qǐng)求過(guò)來(lái)進(jìn)行創(chuàng)建,后續(xù)再考慮池化操作
     * <p>
     * 創(chuàng)建statemachine
     *
     * @param bizType
     * @param subBizType
     * @return
     */
    public StateMachine<BizOrderStatusEnum, BizOrderStatusChangeEventEnum> createStateMachine(String bizType, String subBizType) {
        if (StringUtils.isBlank(subBizType)) {
            subBizType = "";
        }
        String key = StringUtils.trim(bizType) + StringUtils.trim(subBizType);

        String builderName = bizTypeBuilderMap.get(key);
        if (StringUtils.isBlank(builderName)) {
            throw new BusinessException(BizOrderErrorCode.NO_CORRESPONDING_STATEMACHINE_BUILDER, "當(dāng)前業(yè)務(wù)沒(méi)有對(duì)應(yīng)的狀態(tài)機(jī)配置,請(qǐng)檢查");
        }

        return createStateMachine(builderName);
    }

    /**
     * 創(chuàng)建stateMachine
     * @param builderName
     * @return
     */
    public StateMachine<BizOrderStatusEnum, BizOrderStatusChangeEventEnum> createStateMachine(String builderName) {

        BizOrderStateMachineBuilder builder = builderMap.get(builderName);

        StateMachine<BizOrderStatusEnum, BizOrderStatusChangeEventEnum> stateMachine = null;
        try {
            stateMachine = builder.build(beanFactory);
        } catch (Exception e) {
            e.printStackTrace();
            throw new BusinessException(BizOrderErrorCode.ORDER_GENERIC_EXCEPTION, e.getLocalizedMessage());
        }

        return stateMachine;
    }

    /**
     * Invoked by a BeanFactory after it has set all bean properties supplied
     * (and satisfied BeanFactoryAware and ApplicationContextAware).
     * <p>This method allows the bean instance to perform initialization only
     * possible when all bean properties have been set and to throw an
     * exception in the event of misconfiguration.
     *
     * @throws Exception in the event of misconfiguration (such
     *                   as failure to set an essential property) or if initialization fails.
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        builderMap = builders.stream().collect(Collectors.toMap(
                BizOrderStateMachineBuilder::getName,
                Function.identity()
        ));

        // 暫時(shí)將bizType和subBizType XXX-單筆授信作為key,綁定對(duì)應(yīng)的XXX狀態(tài)機(jī),后續(xù)還需要綁定別的業(yè)務(wù)
        bizTypeBuilderMap.put(BizOrderBizTypeEnum.EMPLOAN.getOrderBizType() + BizOrderSubTypeEnum.SINGLE_AUTH.getBizSubType(),
                WYLOAN_BUILDER_NAME);
        // XXX 不區(qū)分子業(yè)務(wù)類(lèi)型
        bizTypeBuilderMap.put(BizOrderBizTypeEnum.EMPLOAN.getOrderBizType(), WYLOAN_BUILDER_NAME);


    }
}

外部調(diào)用時(shí),只需要使用createStateMachine就可以創(chuàng)建出對(duì)應(yīng)的狀態(tài)機(jī)實(shí)例。

Guard相關(guān)實(shí)現(xiàn)

上文中,每次choice都有至少一個(gè)guard出現(xiàn),但是其實(shí)在action之前也可以指定guard,如果不滿足guard中運(yùn)行的條件(guard返回false),就不會(huì)執(zhí)行對(duì)應(yīng)的action。這里忽略了這個(gè)配置。

上面配置中對(duì)應(yīng)的guard實(shí)現(xiàn)(依然在WYLoanBizOrderStateMachineBuilder中):

    /**
     * 判斷是否要到待借款狀態(tài)
     *
     * @return 如果需要,返回true,否則返回false
     */
    private Guard<BizOrderStatusEnum, BizOrderStatusChangeEventEnum> toWaitBorrowGuard() {
        return context -> {
            String finalOrderStatus = (String) context.getMessageHeader(BizOrderConstants.FINAL_STATUS_KEY);

            if (BizOrderStatusEnum.equals(finalOrderStatus, BizOrderStatusEnum.WAIT_BORROW)) {
                log.debug("toWaitBorrowGurad return true");
                return true;

            }
            log.debug("toWaitBorrowGurad return false");
            return false;
        };
    }

    /**
     * 判斷是否需要用戶實(shí)名
     *
     * @return 如果需要,返回true,否則返回false
     */
    private Guard<BizOrderStatusEnum, BizOrderStatusChangeEventEnum> needNameAuthGurad() {
        return context -> {
            String finalOrderStatus = (String) context.getMessageHeader(BizOrderConstants.FINAL_STATUS_KEY);

            if (BizOrderStatusEnum.equals(finalOrderStatus, BizOrderStatusEnum.WAIT_REAL_NAME_AUTH)) {
                log.debug("needNameAuthGurad return true");
                return true;
            }

            log.debug("needNameAuthGurad return false");
            return false;
        };
    }

    private Guard<BizOrderStatusEnum, BizOrderStatusChangeEventEnum> retryUploadGuard() {

        return context -> {
            // 判斷請(qǐng)求參數(shù)中的targetStatus是否為需要重試upload
            String finalOrderStatus = (String) context.getMessageHeader(BizOrderConstants.FINAL_STATUS_KEY);

            if (BizOrderStatusEnum.equals(finalOrderStatus, BizOrderStatusEnum.WAIT_UPLOAD_IMG)) {
                log.debug("retryUploadGuard return true");
                return true;
            }

            log.debug("retryUploadGuard return false");
            return false;
        };
    }

    /**
     * 判斷是否需要重試補(bǔ)全資料
     *
     * @return 結(jié)果
     */
    private Guard<BizOrderStatusEnum, BizOrderStatusChangeEventEnum> retryCompleteGuard() {

        return context -> {
            // 判斷請(qǐng)求參數(shù)中的targetStatus是否為需要重試complete補(bǔ)全
            String finalOrderStatus = (String) context.getMessageHeader(BizOrderConstants.FINAL_STATUS_KEY);

            if (BizOrderStatusEnum.equals(finalOrderStatus, BizOrderStatusEnum.WAIT_COMPLEMENT)) {
                log.debug("retryCompleteGuard return true");
                return true;
            }

            log.debug("retryCompleteGuard return false");
            return false;

        };
    }

    private Guard<BizOrderStatusEnum, BizOrderStatusChangeEventEnum> toCloseGuard() {

        return context -> {
            // 判斷請(qǐng)求參數(shù)中的targetStatus是否為關(guān)單
            String finalOrderStatus = (String) context.getMessageHeader(BizOrderConstants.FINAL_STATUS_KEY);
            if (BizOrderStatusEnum.equals(finalOrderStatus, BizOrderStatusEnum.CLOSE)) {
                log.debug("toCloseGuard return true");
                return true;
            }

            log.debug("toCloseGuard return false");
            return false;
        };
    }


    private Guard<BizOrderStatusEnum, BizOrderStatusChangeEventEnum> partRepayGuard() {
        return context -> {
            // 判斷請(qǐng)求參數(shù)中的targetStatus是否為關(guān)單
            String finalOrderStatus = (String) context.getMessageHeader(BizOrderConstants.FINAL_STATUS_KEY);
            if (BizOrderStatusEnum.equals(finalOrderStatus, BizOrderStatusEnum.PART_REPAID)) {
                log.debug("partRepayGuard return true");
                return true;
            }

            log.debug("partRepayGuard return false");
            return false;
        };
    }

注意,每個(gè)guard都從messageHeader中獲取了FINAL_STATUS_KEY對(duì)應(yīng)的值,這個(gè)數(shù)據(jù)是由外部系統(tǒng)傳入,然后在每次調(diào)用狀態(tài)機(jī)時(shí)設(shè)置到message中,外部調(diào)用如下:

Message<BizOrderStatusChangeEventEnum> eventMsg = MessageBuilder.withPayload(eventEnum)
                // key 與 status change 時(shí)不同,對(duì)應(yīng)的model也不同
                .setHeader(BizOrderConstants.BIZORDER_CONTEXT_CREATE_KEY, bizOrderCreateRequest)
                // 根據(jù)傳遞過(guò)來(lái)的訂單狀態(tài)決定后續(xù)choice跳轉(zhuǎn)
                .setHeader(BizOrderConstants.FINAL_STATUS_KEY,   bizOrderCreateRequest.getBizOrderCreateModel().getOrderStatus())
                .build();

sendResult = stateMachine.sendEvent(eventMsg);

這里這么實(shí)現(xiàn)的原因是,目前的訂單系統(tǒng)沒(méi)辦法自己判斷某個(gè)條件是否達(dá)成,只能依賴外部參數(shù)傳入。但是如果訂單系統(tǒng)中可以通過(guò)調(diào)用外部服務(wù)做最終判斷,這里guard的實(shí)現(xiàn)就可以系統(tǒng)自己判斷,而不是依賴外部參數(shù)傳入。

Action注入

配置中除了guard之外,另一個(gè)跟業(yè)務(wù)實(shí)現(xiàn)緊密關(guān)聯(lián)的就是Action了,下面將所有的Action注入的代碼羅列如下(注入到WYLoanBizOrderStateMachineBuilder中)

    @Autowired
    @Qualifier("errorHandlerAction")
    private Action<BizOrderStatusEnum, BizOrderStatusChangeEventEnum> errorHandlerAction;

    @Resource(name = "orderCreateAction")
    private Action<BizOrderStatusEnum, BizOrderStatusChangeEventEnum> orderCreateAction;

    @Resource(name = "successAction")
    private Action<BizOrderStatusEnum, BizOrderStatusChangeEventEnum> successAction;

    @Resource(name = "cancelAction")
    private Action<BizOrderStatusEnum, BizOrderStatusChangeEventEnum> cancelAction;

    @Resource(name = "closeAction")
    private Action<BizOrderStatusEnum, BizOrderStatusChangeEventEnum> closeAction;

    @Resource(name = "nameAuthAction")
    private Action<BizOrderStatusEnum, BizOrderStatusChangeEventEnum> nameAuthAction;

    @Resource(name = "needNameAuthAction")
    private Action<BizOrderStatusEnum, BizOrderStatusChangeEventEnum> needNameAuthAction;

    @Resource(name = "waitBorrowAction")
    private Action<BizOrderStatusEnum, BizOrderStatusChangeEventEnum> waitBorrowAction;

    @Resource(name = "hrAuditAction")
    private Action<BizOrderStatusEnum, BizOrderStatusChangeEventEnum> hrAuditAction;

    @Resource(name = "retryCompleteAction")
    private Action<BizOrderStatusEnum, BizOrderStatusChangeEventEnum> retryCompleteAction;

    @Resource(name = "completeAction")
    private Action<BizOrderStatusEnum, BizOrderStatusChangeEventEnum> completeAction;

    @Resource(name = "retryUploadAction")
    private Action<BizOrderStatusEnum, BizOrderStatusChangeEventEnum> retryUploadAction;

    @Resource(name = "uploadAction")
    private Action<BizOrderStatusEnum, BizOrderStatusChangeEventEnum> uploadAction;

    @Resource(name = "befDealRiskAction")
    private Action<BizOrderStatusEnum, BizOrderStatusChangeEventEnum> befDealRiskAction;

    // sign時(shí)需要補(bǔ)充所有必需業(yè)務(wù)數(shù)據(jù)
    @Resource(name = "signAction")
    private Action<BizOrderStatusEnum, BizOrderStatusChangeEventEnum> signAction;

    @Resource(name = "toWaitSignAction")
    private Action<BizOrderStatusEnum, BizOrderStatusChangeEventEnum> toWaitSignAction;

    @Resource(name = "loanAction")
    private Action<BizOrderStatusEnum, BizOrderStatusChangeEventEnum> loanAction;

    @Resource(name = "loanSuccAction")
    private Action<BizOrderStatusEnum, BizOrderStatusChangeEventEnum> loanSuccAction;

    @Resource(name = "genBillAction")
    private Action<BizOrderStatusEnum, BizOrderStatusChangeEventEnum> genBillAction;

    @Resource(name = "overdueAction")
    private Action<BizOrderStatusEnum, BizOrderStatusChangeEventEnum> overdueAction;

    @Resource(name = "partRepayAction")
    private Action<BizOrderStatusEnum, BizOrderStatusChangeEventEnum> partRepayAction;

    @Resource(name = "repaidAction")
    private Action<BizOrderStatusEnum, BizOrderStatusChangeEventEnum> repaidAction;

@Autowired默認(rèn)注入byType,@Qualifier指定對(duì)應(yīng)的beanName,所以二者結(jié)合起來(lái)等同于@Resource的作用。

Action實(shí)現(xiàn)

首先注意errorHandlerAction,這里并沒(méi)有什么業(yè)務(wù)邏輯,只是封裝了異常發(fā)生時(shí)的信息,實(shí)現(xiàn)如下:

    /**
     * 異常處理Action
     *
     * @return action對(duì)象
     */
    @Bean(name = "errorHandlerAction", autowire = Autowire.BY_TYPE)
    public Action<BizOrderStatusEnum, BizOrderStatusChangeEventEnum> errorHandlerAction() {

        return context -> {
            RuntimeException exception = (RuntimeException) context.getException();
            log.error("stateMachine execute error = ", exception);
            context.getStateMachine()
                    .getExtendedState().getVariables()
                    .put(RuntimeException.class, exception);
        };
    }

這里將發(fā)生的異常信息記錄在StateMachineContext中,在外部可以根據(jù)這個(gè)這個(gè)值是否存在來(lái)判斷是否有異常發(fā)生。

其他的Action實(shí)現(xiàn)大同小異:

  1. 從context中獲取狀態(tài)機(jī)
  2. 從context中獲取請(qǐng)求參數(shù)
  3. 打印日志,記錄狀態(tài)機(jī)信息、請(qǐng)求參數(shù)信息
  4. 通過(guò)注入的bizManager實(shí)現(xiàn)來(lái)處理具體的業(yè)務(wù)邏輯,關(guān)于bizManager,可以參考http://www.itdecent.cn/p/ba744cfd3672文章中BaseBizManager的定義,以及其子類(lèi)AbstractBizManagerImpl的實(shí)現(xiàn)

以訂單創(chuàng)建和訂單待關(guān)閉兩個(gè)Action為例,其對(duì)應(yīng)代碼實(shí)現(xiàn)如下:

    /**
     * 創(chuàng)建訂單
     * @return
     */
    @Bean(name = "orderCreateAction", autowire = Autowire.BY_TYPE)
    public Action<BizOrderStatusEnum, BizOrderStatusChangeEventEnum> orderCreateAction(){

        return context -> {
            // 訂單創(chuàng)建相關(guān)請(qǐng)求
            BizOrderCreateRequest createRequest = (BizOrderCreateRequest) context.getMessageHeader(BizOrderConstants.BIZORDER_CONTEXT_CREATE_KEY);

            // 從context中獲取狀態(tài)機(jī)
            StateMachine<BizOrderStatusEnum, BizOrderStatusChangeEventEnum> stateMachine = context.getStateMachine();

            log.info("order info={},stateMachine id={},uuid={},jump from {} to sign status",
                    createRequest,
                    stateMachine.getId(),
                    stateMachine.getUuid(),
                    stateMachine.getState().getId());

            bizOrderCreateBizManager.process(createRequest);
        };
    }


     /**
     * 自動(dòng)跳轉(zhuǎn)到close的Action
     * <p>
     * 比如超時(shí)未處理,希望關(guān)單,可以使用此action
     *
      * @return action對(duì)象
     */
    @Bean(name = "toCloseAction",autowire = Autowire.BY_TYPE)
    public Action<BizOrderStatusEnum, BizOrderStatusChangeEventEnum> toCloseAction() {
        return context -> {
            StateMachine<BizOrderStatusEnum, BizOrderStatusChangeEventEnum> stateMachine = context.getStateMachine();

            BizOrderStatusRequest statusRequest = (BizOrderStatusRequest) context.getMessageHeader(BizOrderConstants.BIZORDER_CONTEXT_KEY);

            log.info("order info={},stateMachine id={},uuid={}, jump from {} to toClose status",
                    statusRequest,
                    stateMachine.getId(),
                    stateMachine.getUuid(),
                    stateMachine.getState().getId());

            bizOrderToCloseBizManager.process(statusRequest);

        };
    }

相當(dāng)于action只是一層粘連,而具體的實(shí)現(xiàn)則落地在bizManager中。

下一章節(jié)會(huì)展開(kāi)BizManager的實(shí)現(xiàn)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容