状态机之所以强大,是因为始终保证行为是一致的,这使得调试相对容易。这是因为在机器启动时,操作规则是不可更改的。其思想是,应用程序可能存在有限数量的状态,某些预定义的触发器可以将应用程序从一种状态转移到另一种状态。这样的触发器可以基于事件或计时器。
在应用程序之外定义高级逻辑,然后依靠状态机来管理状态要容易得多。您可以通过发送事件、侦听更改或请求当前状态来与状态机交互。
官网地址:https://projects.spring.io/spring-statemachine/
依赖
<dependency>
<groupId>org.springframework.statemachinegroupId>
<artifactId>spring-statemachine-coreartifactId>
<version>2.1.3.RELEASEversion>
dependency>
定义事件和状态枚举类
package com.example.statemachine.constant;
/**
* @author liuteng
*/
public enum OrderEvent {
/** 准备发货 */
READY_SEND("ready_send","准备发货"),
/** 确认收货 */
CONFIRM_ACC("confirm_acc", "确认收货"),
/**退款成功 */
REFUND_SUC("refund_suc", "退款成功");
private String eventCode;
private String eventDesc;
OrderEvent(String eventCode, String eventDesc) {
this.eventCode = eventCode;
this.eventDesc = eventDesc;
}
public String getEventCode() {
return eventCode;
}
public String getEventDesc() {
return eventDesc;
}
}
package com.example.statemachine.constant;
/**
* @author liuteng
*/
public enum OrderStatus {
/** 已支付 */
PAID(20),
/** 已发货 */
SEND(40),
/** 确认收货 */
RECEIVE(60),
/** 已退款 */
RETURN(80);
private Integer code;
OrderStatus(Integer code) {
this.code = code;
}
public Integer getCode() {
return code;
}
public static OrderStatus getOrderStatus(Integer code) {
for (OrderStatus status : OrderStatus.values()) {
if (status.getCode().equals(code)) {
return status;
}
}
return null;
}
}
配置文件
package com.example.statemachine.config;
import com.example.statemachine.bean.Order;
import com.example.statemachine.constant.OrderEvent;
import com.example.statemachine.constant.OrderStatus;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.statemachine.StateMachineContext;
import org.springframework.statemachine.StateMachinePersist;
import org.springframework.statemachine.config.EnableStateMachine;
import org.springframework.statemachine.config.EnumStateMachineConfigurerAdapter;
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
import org.springframework.statemachine.persist.DefaultStateMachinePersister;
import org.springframework.statemachine.persist.StateMachinePersister;
import org.springframework.statemachine.support.DefaultStateMachineContext;
import java.util.EnumSet;
/**
* @author liuteng
*/
@Configuration
@EnableStateMachine(name = "orderStateMachine")
public class StateMachineConfig extends EnumStateMachineConfigurerAdapter<OrderStatus, OrderEvent> {
/**
* 定义状态机初始状态和所有的状态定义
*/
@Override
public void configure(StateMachineStateConfigurer<OrderStatus, OrderEvent> states) throws Exception {
states.withStates().initial(OrderStatus.PAID).states(EnumSet.allOf(OrderStatus.class));
}
/**
* 定义状态机状态事件
*/
@Override
public void configure(StateMachineTransitionConfigurer<OrderStatus, OrderEvent> transitions) throws Exception {
transitions.withExternal()
.source(OrderStatus.PAID).target(OrderStatus.SEND)
.event(OrderEvent.READY_SEND)
.and()
.withExternal()
.source(OrderStatus.SEND).target(OrderStatus.RECEIVE)
.event(OrderEvent.CONFIRM_ACC)
.and()
.withExternal()
.source(OrderStatus.RECEIVE).target(OrderStatus.RETURN)
.event(OrderEvent.REFUND_SUC);
}
/**
* 状态机状态与订单状态的同步
*/
@Bean
public StateMachinePersister<OrderStatus, OrderEvent, Order> persister() {
return new DefaultStateMachinePersister<>(new StateMachinePersist<OrderStatus, OrderEvent, Order>() {
@Override
public void write(StateMachineContext<OrderStatus, OrderEvent> context, Order order) {
order.setStatus(context.getState().getCode());
}
@Override
public StateMachineContext<OrderStatus, OrderEvent> read(Order order) {
return new DefaultStateMachineContext<>(OrderStatus.getOrderStatus(order.getStatus()), null, null, null);
}
});
}
}
service
package com.example.statemachine.service.impl;
import com.example.statemachine.bean.Order;
import com.example.statemachine.constant.OrderEvent;
import com.example.statemachine.constant.OrderStatus;
import com.example.statemachine.service.OrderStatusManageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.persist.StateMachinePersister;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* @author liuteng
*/
@Service
public class OrderStatusManageServiceImpl implements OrderStatusManageService {
@Resource
private StateMachine<OrderStatus, OrderEvent> orderStateMachine;
@Autowired
private StateMachinePersister<OrderStatus, OrderEvent, Order> persister;
@Override
public boolean modifyOrderStatus(OrderEvent event, Order order) {
boolean result = false;
try {
orderStateMachine.start();
persister.restore(orderStateMachine, order);
Message<OrderEvent> message = MessageBuilder.withPayload(event).setHeader("order", order).build();
result = orderStateMachine.sendEvent(message);
result = orderStateMachine.sendEvent(event);
persister.persist(orderStateMachine, order);
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
}
测试
package com.example.statemachine;
import com.example.statemachine.bean.Order;
import com.example.statemachine.constant.OrderEvent;
import com.example.statemachine.constant.OrderStatus;
import com.example.statemachine.service.OrderStatusManageService;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
/**
* @author liuteng
*/
@SpringBootApplication
public class StateMachineApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(StateMachineApplication.class, args);
OrderStatusManageService orderStatusManageService = context.getBean(OrderStatusManageService.class);
Order order = new Order();
order.setOid("1001200006");
order.setStatus(OrderStatus.PAID.getCode());
boolean result = orderStatusManageService.modifyOrderStatus(OrderEvent.READY_SEND, order);
if (result) {
// TODO ....
}
}
}
监听状态机
package com.example.statemachine.listener;
import com.example.statemachine.bean.Order;
import com.example.statemachine.constant.OrderEvent;
import com.example.statemachine.constant.OrderStatus;
import org.springframework.messaging.Message;
import org.springframework.statemachine.annotation.OnTransition;
import org.springframework.statemachine.annotation.WithStateMachine;
import org.springframework.stereotype.Component;
import java.util.Optional;
/**
* @author liuteng
* 状态机监听器
*/
@Component
@WithStateMachine(name = "orderStateMachine")
public class OrderStatusListener {
private static final String FORMAT = "事件: %s 单号: %s, 状态: %s";
@OnTransition(source = "PAID", target = "SEND")
public boolean sendTransition(Message<OrderEvent> message) {
Order order = (Order) message.getHeaders().get("order");
Optional.ofNullable(order).ifPresent(ord -> {
order.setStatus(OrderStatus.SEND.getCode());
System.out.println(String.format(FORMAT, message.getPayload().getEventCode(), ord.getOid(), ord.getStatus()));
// TODO 持久化
});
return true;
}
@OnTransition(source = "SEND", target = "RECEIVE")
public boolean receiveTransition(Message<OrderEvent> message) {
Order order = (Order) message.getHeaders().get("order");
Optional.ofNullable(order).ifPresent(ord -> {
order.setStatus(OrderStatus.RECEIVE.getCode());
System.out.println(String.format(FORMAT, message.getPayload().getEventCode(), ord.getOid(), ord.getStatus()));
// TODO 持久化
});
return true;
}
@OnTransition(source = "RECEIVE", target = "RETURN")
public boolean returnTransition(Message<OrderEvent> message){
Order order = (Order) message.getHeaders().get("order");
Optional.ofNullable(order).ifPresent(ord -> {
order.setStatus(OrderStatus.RETURN.getCode());
System.out.println(String.format(FORMAT, message.getPayload().getEventCode(), ord.getOid(), ord.getStatus()));
// TODO 持久化
});
return true;
}
}
结果
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.3.0.RELEASE)
2020-06-04 17:25:56.773 INFO 14020 --- [ main] c.e.s.StateMachineApplication : Starting StateMachineApplication on P17751033130 with PID 14020 (D:\myProject\state_machine\target\classes started by 17751033130 in D:\myProject\state_machine)
2020-06-04 17:25:56.775 INFO 14020 --- [ main] c.e.s.StateMachineApplication : No active profile set, falling back to default profiles: default
2020-06-04 17:25:57.156 INFO 14020 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.statemachine.config.configuration.StateMachineAnnotationPostProcessorConfiguration' of type [org.springframework.statemachine.config.configuration.StateMachineAnnotationPostProcessorConfiguration$$EnhancerBySpringCGLIB$$b6c390ca] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2020-06-04 17:25:57.305 INFO 14020 --- [ main] c.e.s.StateMachineApplication : Started StateMachineApplication in 0.929 seconds (JVM running for 1.661)
2020-06-04 17:25:57.313 INFO 14020 --- [ main] o.s.s.support.LifecycleObjectSupport : started org.springframework.statemachine.support.DefaultStateMachineExecutor@6b00f608
2020-06-04 17:25:57.313 INFO 14020 --- [ main] o.s.s.support.LifecycleObjectSupport : started RETURN PAID RECEIVE SEND / PAID / uuid=9bfb49ee-bbb7-4f7b-9850-653ef746b392 / id=null
2020-06-04 17:25:57.313 INFO 14020 --- [ main] o.s.s.support.LifecycleObjectSupport : stopped org.springframework.statemachine.support.DefaultStateMachineExecutor@6b00f608
2020-06-04 17:25:57.314 INFO 14020 --- [ main] o.s.s.support.LifecycleObjectSupport : stopped RETURN PAID RECEIVE SEND / / uuid=9bfb49ee-bbb7-4f7b-9850-653ef746b392 / id=null
2020-06-04 17:25:57.314 INFO 14020 --- [ main] o.s.s.support.LifecycleObjectSupport : started ObjectState [getIds()=[PAID], getClass()=class org.springframework.statemachine.state.ObjectState, hashCode()=544386226, toString()=AbstractState [id=PAID, pseudoState=org.springframework.statemachine.state.DefaultPseudoState@50ecde95, deferred=[], entryActions=[], exitActions=[], stateActions=[], regions=[], submachine=null]]
2020-06-04 17:25:57.315 INFO 14020 --- [ main] o.s.s.support.LifecycleObjectSupport : started org.springframework.statemachine.support.DefaultStateMachineExecutor@6b00f608
2020-06-04 17:25:57.315 INFO 14020 --- [ main] o.s.s.support.LifecycleObjectSupport : started RETURN PAID RECEIVE SEND / PAID / uuid=9bfb49ee-bbb7-4f7b-9850-653ef746b392 / id=null
事件: ready_send 单号: 1001200006, 状态: 40
2020-06-04 17:25:57.327 INFO 14020 --- [extShutdownHook] o.s.s.support.LifecycleObjectSupport : stopped org.springframework.statemachine.support.DefaultStateMachineExecutor@6b00f608
2020-06-04 17:25:57.327 INFO 14020 --- [extShutdownHook] o.s.s.support.LifecycleObjectSupport : stopped RETURN PAID RECEIVE SEND / / uuid=9bfb49ee-bbb7-4f7b-9850-653ef746b392 / id=null
2020-06-04 17:25:57.327 INFO 14020 --- [extShutdownHook] o.s.s.support.LifecycleObjectSupport : destroy called
Process finished with exit code 0