狀態(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)大同小異:
- 從context中獲取狀態(tài)機(jī)
- 從context中獲取請(qǐng)求參數(shù)
- 打印日志,記錄狀態(tài)機(jī)信息、請(qǐng)求參數(shù)信息
- 通過(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)。