1、什么是状况机

1.1 什么是状况

先来解释什么是“状况”( State )。实际事物是有不同状况的,例如一个主动门,就有 open 和 closed 两种状况。咱们通常所说的状况机是有限状况机,也便是被描绘的事物的状况的数量是有限个,例如主动门的状况便是两个 open 和 closed 。

Java架构-状态机如何实现

状况机,也便是 State Machine ,不是指一台实际机器,而是指一个数学模型。说白了,一般便是指一张状况转化图。例如,依据主动门的运转规矩,咱们能够笼统出下面这么一个图。

主动门有两个状况,open 和 closed ,closed 状况下,假如读取开门信号,那么状况就会切换为 open 。open 状况下假如读取关门信号,状况就会切换为 closed 。

状况机的全称是有限状况主动机,主动两个字也是包括重要意义的。给定一个状况机,同时给定它的当时状况以及输入,那么输出状况时能够清晰的运算出来的。例如关于主动门,给定初始状况 closed ,给定输入“开门”,那么下一个状况时能够运算出来的。

这样状况机的基本界说咱们就介绍完毕了。重复一下:状况机是有限状况主动机的简称,是实际事物运转规矩笼统而成的一个数学模型。

1.2 四大概念

下面来给出状况机的四大概念。

  • 第一个是 State ,状况。一个状况机至少要包括两个状况。例如上面主动门的比如,有 open 和 closed 两个状况。
  • 第二个是 Event ,事情。事情便是履行某个操作的触发条件或许口令。关于主动门,“按下开门按钮”便是一个事情。
  • 第三个是 Action ,动作。事情产生以后要履行动作。例如事情是“按开门按钮”,动作是“开门”。编程的时分,一个 Action一般就对应一个函数。
  • 第四个是 Transition ,改换。也便是从一个状况变化为另一个状况。例如“开门过程”便是一个改换。

1.3 状况机

有限状况机(Finite-state machine,FSM),又称有限状况主动机,简称状况机,是表示有限个状况以及在这些状况之间的搬运和动作等行为的数学模型。

FSM是一种算法思想,简略而言,有限状况机由一组状况、一个初始状况、输入和依据输入及现有状况转化为下一个状况的转化函数组成。

其效果主要是描绘方针在它的生命周期内所阅历的状况序列,以及怎么呼应来自外界的各种事情。

Java攻略:java-family.cn

2、状况机图

做需求时,需求了解以下六种元素:开端、停止、现态、次态(方针状况)、动作、条件,咱们就能够完结一个状况机图了:

以订单为例:以从待付出状况转化为待发货状况为例

Java架构-状态机如何实现

  • ①现态:是指当时所在的状况。待付出
  • ②条件:又称为“事情”,当一个条件被满意,将会触发一个动作,或许履行一次状况的迁移。付出事情
  • ③动作:条件满意后履行的动作。动作履行完毕后,能够迁移到新的状况,也能够仍旧保持原状况。动作不是必需的,当条件满意后,也能够不履行任何动作,直接迁移到新状况。状况转化为待发货
  • ④次态:条件满意后要迁往的新状况。“次态”是相关于“现态”而言的,“次态”一旦被激活,就转变成新的“现态”了。待发货 注意事项

1、防止把某个“程序动作”当作是一种“状况”来处理。那么怎么区分“动作”和“状况”?“动作”是不稳定的,即使没有条件的触发,“动作”一旦履行完毕就完毕了;而“状况”是相对稳定的,假如没有外部条件的触发,一个状况会一向继续下去。

2、状况划分时漏掉一些状况,导致跳转逻辑不完整。所以在规划状况机时,咱们需求重复的检查规划的状况图或许状况表,终究达到一种牢不可破的规划方案。

3、spring statemachine

3.1 状况机spring statemachine 概述

Spring Statemachine是应用程序开发人员在Spring应用程序中运用状况机概念的结构

Spring Statemachine旨在提供以下功用:

  1. 易于运用的扁平单级状况机,用于简略的运用事例。
  2. 分层状况机结构,以简化复杂的状况装备。
  3. 状况机区域提供更复杂的状况装备。
  4. 运用触发器,转化,保镳和操作。
  5. 键入安全装备适配器。
  6. 生成器模式,用于在Spring Application上下文之外运用的简略实例化通常用例的食谱
  7. 依据Zookeeper的分布式状况机
  8. 状况机事情监听器。
  9. UML Eclipse Papyrus建模。
  10. 将计算机装备存储在永久存储中。
  11. Spring IOC集成将bean与状况机关联起来。

状况机功用强大,由于行为始终确保共同,使调试相对简单。这是由于操作规矩是在机器发动时写成的。这个想法是你的应用程序可能存在于有限数量的状况中,某些预界说的触发器能够将你的应用程序从一个状况搬运到另一个状况。此类触发器能够依据事情或计时器。

在应用程序之外界说高档逻辑然后依靠状况机来管理状况要简单得多。您能够经过发送事情,侦听更改或仅恳求当时状况来与状况机进行交互。

官网:spring.io/projects/sp…

3.2 快速开端

以订单状况改变的比如为例:

表结构规划如下:

CREATETABLE`tb_order`(
`id`bigint(20)unsignedNOTNULLAUTO_INCREMENTCOMMENT'主键ID',
`order_code`varchar(128)COLLATEutf8mb4_binDEFAULTNULLCOMMENT'订单编码',
`status`smallint(3)DEFAULTNULLCOMMENT'订单状况',
`name`varchar(64)COLLATEutf8mb4_binDEFAULTNULLCOMMENT'订单称号',
`price`decimal(12,2)DEFAULTNULLCOMMENT'价格',
`delete_flag`tinyint(2)NOTNULLDEFAULT'0'COMMENT'删除符号,0未删除1已删除',
`create_time`timestampNOTNULLDEFAULTCURRENT_TIMESTAMPONUPDATECURRENT_TIMESTAMPCOMMENT'创立时刻',
`update_time`timestampNOTNULLDEFAULT'0000-00-0000:00:00'COMMENT'更新时刻',
`create_user_code`varchar(32)COLLATEutf8mb4_binDEFAULTNULLCOMMENT'创立人',
`update_user_code`varchar(32)COLLATEutf8mb4_binDEFAULTNULLCOMMENT'更新人',
`version`int(11)NOTNULLDEFAULT'0'COMMENT'版本号',
`remark`varchar(64)COLLATEutf8mb4_binDEFAULTNULLCOMMENT'备注',
PRIMARYKEY(`id`)
)ENGINE=InnoDBAUTO_INCREMENT=6DEFAULTCHARSET=utf8mb4COLLATE=utf8mb4_binCOMMENT='订单表';

/*Dataforthetable`tb_order`*/

insertinto`tb_order`(`id`,`order_code`,`status`,`name`,`price`,`delete_flag`,`create_time`,`update_time`,`create_user_code`,`update_user_code`,`version`,`remark`)values
(2,'A111',1,'A','22.00',0,'2022-10-1516:14:11','2022-10-0221:29:14','zhangsan','zhangsan',0,NULL),
(3,'A111',1,'订单A','22.00',0,'2022-10-0221:53:13','2022-10-0221:29:14','zhangsan','zhangsan',0,NULL),
(4,'A111',1,'订单A','22.00',0,'2022-10-0221:53:13','2022-10-0221:29:14','zhangsan','zhangsan',0,NULL),
(5,'A111',1,'订单A','22.00',0,'2022-10-0309:08:30','2022-10-0221:29:14','zhangsan','zhangsan',0,NULL);
1)引进依靠
<!--redis耐久化状况机-->
<dependency>
<groupId>org.springframework.statemachine</groupId>
<artifactId>spring-statemachine-redis</artifactId>
<version>1.2.9.RELEASE</version>
</dependency>
<!--状况机-->
<dependency>
<groupId>org.springframework.statemachine</groupId>
<artifactId>spring-statemachine-starter</artifactId>
<version>2.0.1.RELEASE</version>
</dependency>
2)界说状况机状况和事情

状况枚举:

/**
* 
*/
publicenumOrderStatus{
//待付出,待发货,待收货,已完结
WAIT_PAYMENT(1,"待付出"),
WAIT_DELIVER(2,"待发货"),
WAIT_RECEIVE(3,"待收货"),
FINISH(4,"已完结");
privateIntegerkey;
privateStringdesc;
OrderStatus(Integerkey,Stringdesc){
this.key=key;
this.desc=desc;
}
publicIntegergetKey(){
returnkey;
}
publicStringgetDesc(){
returndesc;
}
publicstaticOrderStatusgetByKey(Integerkey){
for(OrderStatuse:values()){
if(e.getKey().equals(key)){
returne;
}
}
thrownewRuntimeException("enumnotexists.");
}
}

事情:

/**
* 
*/
publicenumOrderStatusChangeEvent{
//付出,发货,承认收货
PAYED,DELIVERY,RECEIVED;
}
3)界说状况机规矩和装备状况机
@Configuration
@EnableStateMachine(name="orderStateMachine")
publicclassOrderStateMachineConfigextendsStateMachineConfigurerAdapter<OrderStatus,OrderStatusChangeEvent>{
/**
*装备状况
*
*@paramstates
*@throwsException
*/
publicvoidconfigure(StateMachineStateConfigurer<OrderStatus,OrderStatusChangeEvent>states)throwsException{
states
.withStates()
.initial(OrderStatus.WAIT_PAYMENT)
.states(EnumSet.allOf(OrderStatus.class));
}
/**
*装备状况转化事情联系
*
*@paramtransitions
*@throwsException
*/
publicvoidconfigure(StateMachineTransitionConfigurer<OrderStatus,OrderStatusChangeEvent>transitions)throwsException{
transitions
//付出事情:待付出-》待发货
.withExternal().source(OrderStatus.WAIT_PAYMENT).target(OrderStatus.WAIT_DELIVER).event(OrderStatusChangeEvent.PAYED)
.and()
//发货事情:待发货-》待收货
.withExternal().source(OrderStatus.WAIT_DELIVER).target(OrderStatus.WAIT_RECEIVE).event(OrderStatusChangeEvent.DELIVERY)
.and()
//收货事情:待收货-》已完结
.withExternal().source(OrderStatus.WAIT_RECEIVE).target(OrderStatus.FINISH).event(OrderStatusChangeEvent.RECEIVED);
}
}

装备耐久化:

/**
* 
*/
@Configuration
@Slf4j
publicclassPersist<E,S>{
/**
*耐久化到内存map中
*
*@return
*/
@Bean(name="stateMachineMemPersister")
publicstaticStateMachinePersistergetPersister(){
returnnewDefaultStateMachinePersister(newStateMachinePersist(){
@Override
publicvoidwrite(StateMachineContextcontext,ObjectcontextObj)throwsException{
log.info("耐久化状况机,context:{},contextObj:{}",JSON.toJSONString(context),JSON.toJSONString(contextObj));
map.put(contextObj,context);
}
@Override
publicStateMachineContextread(ObjectcontextObj)throwsException{
log.info("获取状况机,contextObj:{}",JSON.toJSONString(contextObj));
StateMachineContextstateMachineContext=(StateMachineContext)map.get(contextObj);
log.info("获取状况机成果,stateMachineContext:{}",JSON.toJSONString(stateMachineContext));
returnstateMachineContext;
}
privateMapmap=newHashMap();
});
}

@Resource
privateRedisConnectionFactoryredisConnectionFactory;
/**
*耐久化到redis中,在分布式系统中运用
*
*@return
*/
@Bean(name="stateMachineRedisPersister")
publicRedisStateMachinePersister<E,S>getRedisPersister(){
RedisStateMachineContextRepository<E,S>repository=newRedisStateMachineContextRepository<>(redisConnectionFactory);
RepositoryStateMachinePersistp=newRepositoryStateMachinePersist<>(repository);
returnnewRedisStateMachinePersister<>(p);
}
}
4)事务系统

controller:

/**
* 
*/
@RestController
@RequestMapping("/order")
publicclassOrderController{
@Resource
privateOrderServiceorderService;
/**
*依据id查询订单
*
*@return
*/
@RequestMapping("/getById")
publicOrdergetById(@RequestParam("id")Longid){
//依据id查询订单
Orderorder=orderService.getById(id);
returnorder;
}
/**
*创立订单
*
*@return
*/
@RequestMapping("/create")
publicStringcreate(@RequestBodyOrderorder){
//创立订单
orderService.create(order);
return"sucess";
}
/**
*对订单进行付出
*
*@paramid
*@return
*/
@RequestMapping("/pay")
publicStringpay(@RequestParam("id")Longid){
//对订单进行付出
orderService.pay(id);
return"success";
}

/**
*对订单进行发货
*
*@paramid
*@return
*/
@RequestMapping("/deliver")
publicStringdeliver(@RequestParam("id")Longid){
//对订单进行承认收货
orderService.deliver(id);
return"success";
}
/**
*对订单进行承认收货
*
*@paramid
*@return
*/
@RequestMapping("/receive")
publicStringreceive(@RequestParam("id")Longid){
//对订单进行承认收货
orderService.receive(id);
return"success";
}
}

servie:

/**
* 
*/
@Service("orderService")
@Slf4j
publicclassOrderServiceImplextendsServiceImpl<OrderMapper,Order>implementsOrderService{
@Resource
privateStateMachine<OrderStatus,OrderStatusChangeEvent>orderStateMachine;
@Resource
privateStateMachinePersister<OrderStatus,OrderStatusChangeEvent,String>stateMachineMemPersister;
@Resource
privateOrderMapperorderMapper;
/**
*创立订单
*
*@paramorder
*@return
*/
publicOrdercreate(Orderorder){
order.setStatus(OrderStatus.WAIT_PAYMENT.getKey());
orderMapper.insert(order);
returnorder;
}
/**
*对订单进行付出
*
*@paramid
*@return
*/
publicOrderpay(Longid){
Orderorder=orderMapper.selectById(id);
log.info("线程称号:{},测验付出,订单号:{}",Thread.currentThread().getName(),id);
if(!sendEvent(OrderStatusChangeEvent.PAYED,order)){
log.error("线程称号:{},付出失利, 状况反常,订单信息:{}",Thread.currentThread().getName(),order);
thrownewRuntimeException("付出失利,订单状况反常");
}
returnorder;
}
/**
*对订单进行发货
*
*@paramid
*@return
*/
publicOrderdeliver(Longid){
Orderorder=orderMapper.selectById(id);
log.info("线程称号:{},测验发货,订单号:{}",Thread.currentThread().getName(),id);
if(!sendEvent(OrderStatusChangeEvent.DELIVERY,order)){
log.error("线程称号:{},发货失利, 状况反常,订单信息:{}",Thread.currentThread().getName(),order);
thrownewRuntimeException("发货失利,订单状况反常");
}
returnorder;
}
/**
*对订单进行承认收货
*
*@paramid
*@return
*/
publicOrderreceive(Longid){
Orderorder=orderMapper.selectById(id);
log.info("线程称号:{},测验收货,订单号:{}",Thread.currentThread().getName(),id);
if(!sendEvent(OrderStatusChangeEvent.RECEIVED,order)){
log.error("线程称号:{},收货失利, 状况反常,订单信息:{}",Thread.currentThread().getName(),order);
thrownewRuntimeException("收货失利,订单状况反常");
}
returnorder;
}
/**
*发送订单状况转化事情
*synchronized润饰确保这个办法是线程安全的
*
*@paramchangeEvent
*@paramorder
*@return
*/
privatesynchronizedbooleansendEvent(OrderStatusChangeEventchangeEvent,Orderorder){
booleanresult=false;
try{
//发动状况机
orderStateMachine.start();
//测验康复状况机状况
stateMachineMemPersister.restore(orderStateMachine,String.valueOf(order.getId()));
Messagemessage=MessageBuilder.withPayload(changeEvent).setHeader("order",order).build();
result=orderStateMachine.sendEvent(message);
//耐久化状况机状况
stateMachineMemPersister.persist(orderStateMachine,String.valueOf(order.getId()));
}catch(Exceptione){
log.error("订单操作失利:{}",e);
}finally{
orderStateMachine.stop();
}
returnresult;
}
}

监听状况的变化:

/**
* 
*/
@Component("orderStateListener")
@WithStateMachine(name="orderStateMachine")
@Slf4j
publicclassOrderStateListenerImpl{
@Resource
privateOrderMapperorderMapper;

@OnTransition(source="WAIT_PAYMENT",target="WAIT_DELIVER")
publicvoidpayTransition(Message<OrderStatusChangeEvent>message){
Orderorder=(Order)message.getHeaders().get("order");
log.info("付出,状况机反应信息:{}",message.getHeaders().toString());
//更新订单
order.setStatus(OrderStatus.WAIT_DELIVER.getKey());
orderMapper.updateById(order);
//TODO其他事务
}
@OnTransition(source="WAIT_DELIVER",target="WAIT_RECEIVE")
publicvoiddeliverTransition(Message<OrderStatusChangeEvent>message){
Orderorder=(Order)message.getHeaders().get("order");
log.info("发货,状况机反应信息:{}",message.getHeaders().toString());
//更新订单
order.setStatus(OrderStatus.WAIT_RECEIVE.getKey());
orderMapper.updateById(order);
//TODO其他事务
}
@OnTransition(source="WAIT_RECEIVE",target="FINISH")
publicvoidreceiveTransition(Message<OrderStatusChangeEvent>message){
Orderorder=(Order)message.getHeaders().get("order");
log.info("承认收货,状况机反应信息:{}",message.getHeaders().toString());
//更新订单
order.setStatus(OrderStatus.FINISH.getKey());
orderMapper.updateById(order);
//TODO其他事务
}
}

3.3 测验验证

1)验证事务
  • 新增一个订单

    http://localhost:8084/order/create

  • 对订单进行付出

    http://localhost:8084/order/pay?id=2

  • 对订单进行发货

    http://localhost:8084/order/deliver?id=2

  • 对订单进行承认收货

    http://localhost:8084/order/receive?id=2

正常流程完毕。假如对一个订单进行付出了,再次进行付出,则会报错:http://localhost:8084/order/pay?id=2

报错如下:

Java架构-状态机如何实现

2)验证耐久化

内存

运用内存耐久化类耐久化:

/**
* 
*/
@Resource
privateStateMachinePersister<OrderStatus,OrderStatusChangeEvent,String>stateMachineMemPersister;

/**
*发送订单状况转化事情
*synchronized润饰确保这个办法是线程安全的
*
*@paramchangeEvent
*@paramorder
*@return
*/
privatesynchronizedbooleansendEvent(OrderStatusChangeEventchangeEvent,Orderorder){
booleanresult=false;
try{
//发动状况机
orderStateMachine.start();
//测验康复状况机状况
stateMachineMemPersister.restore(orderStateMachine,String.valueOf(order.getId()));
Messagemessage=MessageBuilder.withPayload(changeEvent).setHeader("order",order).build();
result=orderStateMachine.sendEvent(message);
//耐久化状况机状况
stateMachineMemPersister.persist(orderStateMachine,String.valueOf(order.getId()));
}catch(Exceptione){
log.error("订单操作失利:{}",e);
}finally{
orderStateMachine.stop();
}
returnresult;
}

redis耐久化

引进依靠:

<!--redis耐久化状况机-->
<dependency>
<groupId>org.springframework.statemachine</groupId>
<artifactId>spring-statemachine-redis</artifactId>
<version>1.2.9.RELEASE</version>
</dependency>

装备yaml:

spring:
redis:
database:0
host:localhost
jedis:
pool:
max-active:8
max-idle:8
max-wait:''
min-idle:0
password:''
port:6379
timeout:0

运用redis耐久化类耐久化:

/**
* 
*/
@Resource
privateStateMachinePersister<OrderStatus,OrderStatusChangeEvent,String>stateMachineRedisPersister;

/**
*发送订单状况转化事情
*synchronized润饰确保这个办法是线程安全的
*
*@paramchangeEvent
*@paramorder
*@return
*/
privatesynchronizedbooleansendEvent(OrderStatusChangeEventchangeEvent,Orderorder){
booleanresult=false;
try{
//发动状况机
orderStateMachine.start();
//测验康复状况机状况
stateMachineRedisPersister.restore(orderStateMachine,String.valueOf(order.getId()));
Messagemessage=MessageBuilder.withPayload(changeEvent).setHeader("order",order).build();
result=orderStateMachine.sendEvent(message);
//耐久化状况机状况
stateMachineRedisPersister.persist(orderStateMachine,String.valueOf(order.getId()));
}catch(Exceptione){
log.error("订单操作失利:{}",e);
}finally{
orderStateMachine.stop();
}
returnresult;
}

3.4 状况机存在的问题

1)stateMachine无法抛出反常,反常会被状况机给消化掉

问题现象

从orderStateMachine.sendEvent(message);获取的成果无法感知到。不管履行正常仍是抛出反常,都回来true。

@Resource
privateOrderMapperorderMapper;

@Resource
privateStateMachine<OrderStatus,OrderStatusChangeEvent>orderStateMachine;

@OnTransition(source="WAIT_PAYMENT",target="WAIT_DELIVER")
@Transactional(rollbackFor=Exception.class)
publicvoidpayTransition(Message<OrderStatusChangeEvent>message){
Orderorder=(Order)message.getHeaders().get("order");
log.info("付出,状况机反应信息:{}",message.getHeaders().toString());
try{
//更新订单
order.setStatus(OrderStatus.WAIT_DELIVER.getKey());
orderMapper.updateById(order);
//TODO其他事务
//模仿反常
if(Objects.equals(order.getName(),"A")){
thrownewRuntimeException("履行事务反常");
}
}catch(Exceptione){
//假如出现反常,记录反常信息,抛出反常信息进行回滚
log.error("payTransition 出现反常:{}",e);
throwe;
}
}

监听事情抛出反常,在发送事情中无法感知:

privatesynchronizedbooleansendEvent(OrderStatusChangeEventchangeEvent,Orderorder){
booleanresult=false;
try{
//发动状况机
orderStateMachine.start();
//测验康复状况机状况
stateMachineMemPersister.restore(orderStateMachine,String.valueOf(order.getId()));
Messagemessage=MessageBuilder.withPayload(changeEvent).setHeader("order",order).build();
//事情履行反常了,依然回来true,无法感知反常
result=orderStateMachine.sendEvent(message);
if(result){
//耐久化状况机状况,假如依据true耐久化,则会出现问题
stateMachineMemPersister.persist(orderStateMachine,String.valueOf(order.getId()));
}
}catch(Exceptione){
log.error("订单操作失利:{}",e);
}finally{
orderStateMachine.stop();
}
returnresult;
}

调试发现:发送事情和监听事情是一个线程,发送事情的成果是在监听操作履行完之后才回来

Java架构-状态机如何实现
监听线程:

Java架构-状态机如何实现

解决方案:自己保存反常到数据库或许内存中,进行判别

也能够经过接口:org.springframework.statemachine.StateMachine##getExtendedState

办法把履行状况放入这个变量中

publicinterfaceExtendedState{
Map<Object,Object>getVariables();
<T>Tget(Objectvar1,Class<T>var2);
voidsetExtendedStateChangeListener(ExtendedState.ExtendedStateChangeListenervar1);
publicinterfaceExtendedStateChangeListener{
voidchanged(Objectvar1,Objectvar2);
}
}

org.springframework.statemachine.support.DefaultExtendedState##getVariables

privatefinalMap<Object,Object>variables;

publicDefaultExtendedState(){
this.variables=newObservableMap(newConcurrentHashMap(),newDefaultExtendedState.LocalMapChangeListener());
}

publicMap<Object,Object>getVariables(){
returnthis.variables;
}

改造监听状况:把事务的履行成果进行保存,1成功,0失利


@Resource
privateOrderMapperorderMapper;
@Resource
privateStateMachine<OrderStatus,OrderStatusChangeEvent>orderStateMachine;

@OnTransition(source="WAIT_PAYMENT",target="WAIT_DELIVER")
@Transactional(rollbackFor=Exception.class)
publicvoidpayTransition(Message<OrderStatusChangeEvent>message){
Orderorder=(Order)message.getHeaders().get("order");
log.info("付出,状况机反应信息:{}",message.getHeaders().toString());
try{
//更新订单
order.setStatus(OrderStatus.WAIT_DELIVER.getKey());
orderMapper.updateById(order);
//TODO其他事务
//模仿反常
if(Objects.equals(order.getName(),"A")){
thrownewRuntimeException("履行事务反常");
}
//成功则为1
orderStateMachine.getExtendedState().getVariables().put(CommonConstants.payTransition+order.getId(),1);
}catch(Exceptione){
//假如出现反常,则进行回滚
log.error("payTransition 出现反常:{}",e);
//将反常信息变量信息中,失利则为0
orderStateMachine.getExtendedState().getVariables().put(CommonConstants.payTransition+order.getId(),0);
throwe;
}
}

发送事情改造:假如获取到事务履行反常,则回来失利,不进行状况机耐久化 com.zengqingfa.springboot.state.demo.service.impl.OrderServiceImpl##sendEvent

@Resource
privateStateMachine<OrderStatus,OrderStatusChangeEvent>orderStateMachine;
@Resource
privateStateMachinePersister<OrderStatus,OrderStatusChangeEvent,String>stateMachineMemPersister;

/**
*发送订单状况转化事情
*synchronized润饰确保这个办法是线程安全的
*
*@paramchangeEvent
*@paramorder
*@return
*/
privatesynchronizedbooleansendEvent(OrderStatusChangeEventchangeEvent,Orderorder){
booleanresult=false;
try{
//发动状况机
orderStateMachine.start();
//测验康复状况机状况
stateMachineMemPersister.restore(orderStateMachine,String.valueOf(order.getId()));
Messagemessage=MessageBuilder.withPayload(changeEvent).setHeader("order",order).build();
result=orderStateMachine.sendEvent(message);
if(!result){
returnfalse;
}
//获取到监听的成果信息
Integero=(Integer)orderStateMachine.getExtendedState().getVariables().get(CommonConstants.payTransition+order.getId());
//操作完结之后,删除本次对应的key信息
orderStateMachine.getExtendedState().getVariables().remove(CommonConstants.payTransition+order.getId());
//假如事务履行成功,则耐久化状况机
if(Objects.equals(1,Integer.valueOf(o))){
//耐久化状况机状况
stateMachineMemPersister.persist(orderStateMachine,String.valueOf(order.getId()));
}else{
//订单履行事务反常
returnfalse;
}
}catch(Exceptione){
log.error("订单操作失利:{}",e);
}finally{
orderStateMachine.stop();
}
returnresult;
}

代码优化

  • 发送事情只针对了付出,假如是非付出事情呢?
//获取到监听的成果信息
Integero=(Integer)orderStateMachine.getExtendedState().getVariables().get(CommonConstants.payTransition+order.getId());
  • 监听设置状况的代码有重复代码,需求进行优化,可运用aop
try{
//TODO其他事务
//成功则为1
orderStateMachine.getExtendedState().getVariables().put(CommonConstants.payTransition+order.getId(),1);
}catch(Exceptione){
//假如出现反常,则进行回滚
log.error("payTransition 出现反常:{}",e);
//将反常信息变量信息中,失利则为0
orderStateMachine.getExtendedState().getVariables().put(CommonConstants.payTransition+order.getId(),0);
throwe;
}

常量类:

publicinterfaceCommonConstants{
StringorderHeader="order";
StringpayTransition="payTransition";
StringdeliverTransition="deliverTransition";
StringreceiveTransition="receiveTransition";
}

付出发送事情:com.zengqingfa.springboot.state.demo.service.impl.OrderServiceImpl##pay

@Resource
privateStateMachine<OrderStatus,OrderStatusChangeEvent>orderStateMachine;
@Resource
privateStateMachinePersister<OrderStatus,OrderStatusChangeEvent,String>stateMachineMemPersister;
@Resource
privateOrderMapperorderMapper;

/**
*对订单进行付出
*
*@paramid
*@return
*/
publicOrderpay(Longid){
Orderorder=orderMapper.selectById(id);
log.info("线程称号:{},测验付出,订单号:{}",Thread.currentThread().getName(),id);
if(!sendEvent(OrderStatusChangeEvent.PAYED,order,CommonConstants.payTransition)){
log.error("线程称号:{},付出失利, 状况反常,订单信息:{}",Thread.currentThread().getName(),order);
thrownewRuntimeException("付出失利,订单状况反常");
}
returnorder;
}

/**
*发送订单状况转化事情
*synchronized润饰确保这个办法是线程安全的
*
*@paramchangeEvent
*@paramorder
*@return
*/
privatesynchronizedbooleansendEvent(OrderStatusChangeEventchangeEvent,Orderorder,Stringkey){
booleanresult=false;
try{
//发动状况机
orderStateMachine.start();
//测验康复状况机状况
stateMachineMemPersister.restore(orderStateMachine,String.valueOf(order.getId()));
Messagemessage=MessageBuilder.withPayload(changeEvent).setHeader("order",order).build();
result=orderStateMachine.sendEvent(message);
if(!result){
returnfalse;
}
//获取到监听的成果信息
Integero=(Integer)orderStateMachine.getExtendedState().getVariables().get(key+order.getId());
//操作完结之后,删除本次对应的key信息
orderStateMachine.getExtendedState().getVariables().remove(key+order.getId());
//假如事务履行成功,则耐久化状况机
if(Objects.equals(1,Integer.valueOf(o))){
//耐久化状况机状况
stateMachineMemPersister.persist(orderStateMachine,String.valueOf(order.getId()));
}else{
//订单履行事务反常
returnfalse;
}
}catch(Exceptione){
log.error("订单操作失利:{}",e);
}finally{
orderStateMachine.stop();
}
returnresult;
}

运用aop对监听事情切面,把事务履行成果封装到状况机的变量中,注解:

@Retention(RetentionPolicy.RUNTIME)
public@interfaceLogResult{
/**
*履行的事务key
*
*@returnString
*/
Stringkey();
}

切面:

@Component
@Aspect
@Slf4j
publicclassLogResultAspect{

//阻拦LogHistory注解
@Pointcut("@annotation(com.zengqingfa.springboot.state.demo.aop.annotation.LogResult)")
privatevoidlogResultPointCut(){
//logResultPointCut日志注解切点
}
@Resource
privateStateMachine<OrderStatus,OrderStatusChangeEvent>orderStateMachine;

@Around("logResultPointCut()")
publicObjectlogResultAround(ProceedingJoinPointpjp)throwsThrowable{
//获取参数
Object[]args=pjp.getArgs();
log.info("参数args:{}",args);
Messagemessage=(Message)args[0];
Orderorder=(Order)message.getHeaders().get("order");
//获取办法
Methodmethod=((MethodSignature)pjp.getSignature()).getMethod();
//获取LogHistory注解
LogResultlogResult=method.getAnnotation(LogResult.class);
Stringkey=logResult.key();
ObjectreturnVal=null;
try{
//履行办法
returnVal=pjp.proceed();
//假如事务履行正常,则保存信息
//成功则为1
orderStateMachine.getExtendedState().getVariables().put(key+order.getId(),1);
}catch(Throwablee){
log.error("e:{}",e.getMessage());
//假如事务履行反常,则保存信息
//将反常信息变量信息中,失利则为0
orderStateMachine.getExtendedState().getVariables().put(key+order.getId(),0);
throwe;
}
returnreturnVal;
}
}

监听类运用注解:

@Component("orderStateListener")
@WithStateMachine(name="orderStateMachine")
@Slf4j
publicclassOrderStateListenerImpl{
@Resource
privateOrderMapperorderMapper;

@OnTransition(source="WAIT_PAYMENT",target="WAIT_DELIVER")
@Transactional(rollbackFor=Exception.class)
@LogResult(key=CommonConstants.payTransition)
publicvoidpayTransition(Message<OrderStatusChangeEvent>message){
Orderorder=(Order)message.getHeaders().get("order");
log.info("付出,状况机反应信息:{}",message.getHeaders().toString());
//更新订单
order.setStatus(OrderStatus.WAIT_DELIVER.getKey());
orderMapper.updateById(order);
//TODO其他事务
//模仿反常
if(Objects.equals(order.getName(),"A")){
thrownewRuntimeException("履行事务反常");
}
}
@OnTransition(source="WAIT_DELIVER",target="WAIT_RECEIVE")
@LogResult(key=CommonConstants.deliverTransition)
publicvoiddeliverTransition(Message<OrderStatusChangeEvent>message){
Orderorder=(Order)message.getHeaders().get("order");
log.info("发货,状况机反应信息:{}",message.getHeaders().toString());
//更新订单
order.setStatus(OrderStatus.WAIT_RECEIVE.getKey());
orderMapper.updateById(order);
//TODO其他事务
}
@OnTransition(source="WAIT_RECEIVE",target="FINISH")
@LogResult(key=CommonConstants.receiveTransition)
publicvoidreceiveTransition(Message<OrderStatusChangeEvent>message){
Orderorder=(Order)message.getHeaders().get("order");
log.info("承认收货,状况机反应信息:{}",message.getHeaders().toString());
//更新订单
order.setStatus(OrderStatus.FINISH.getKey());
orderMapper.updateById(order);
//TODO其他事务
}
}