状态机优势

1、状态机建立的控制中心是跟外界低耦合的,通过event通信;
2、控制中心所有的状态都是预设好的,不会超预料;
3、状态的跳转都是有设定控制条件的,会按照预设的转移路径运动;
4、状态机还非常容易的扩展和变更,支持因业务的发展而变更或扩展复杂业务流程。

Spring Boot StateMachine实现

1、加入依赖

<dependency>
		<groupId>org.springframework.statemachine</groupId>
		<artifactId>spring-statemachine-core</artifactId>
		<version>1.2.0.RELEASE</version>
	</dependency>

2、定义状态枚举和事件枚举

public enum States {
    UNPAID,                 // 待支付
    WAITING_FOR_RECEIVE,    // 待收货
    DONE                    // 结束
}
public enum Events {
    PAY,        // 支付
    RECEIVE     // 收货
}

3、完成状态机配置:状态机的初始状态和所有状态机的转移规则


@Configuration
//启用状态机功能
@EnableStateMachine
public class StateMachineConfig extends EnumStateMachineConfigurerAdapter<States, Events> {
 
	private Logger logger = LoggerFactory.getLogger(getClass());
	
	@Override
	public void configure(StateMachineStateConfigurer<States, Events> states) throws Exception{
		//定义状态机中的状态
		states.withStates()
		        .initial(States.UNPAID) //初始状态
				.states(EnumSet.allOf(States.class));//指定使用上一步定义的所有状态作为该状态机的状态定义
	}
	
	@Override
	public void configure(StateMachineTransitionConfigurer<States, Events> transitions) throws Exception{
		transitions
			.withExternal()
				.source(States.UNPAID).target(States.WAITING_FOR_RECEIVE)  //指定状态来源和目标
				.event(Events.PAY)	//指定触发事件
				.and()
			.withExternal()
				.source(States.WAITING_FOR_RECEIVE).target(States.DONE)
				.event(Events.RECEIVE);
	}
	
	@Override
	public void configure(StateMachineConfigurationConfigurer<States, Events> config) throws Exception{
		config
			.withConfiguration()
				.listener(listener());  //指定状态机的处理监听器
	}
	//创建状态监听器的实例,定义具体的状态迁移处理逻辑,在通常情况将该实例的定义放到独立的类定义中,用注入方式加载进来
	@Bean
	public StateMachineListener<States, Events> listener(){
		return new StateMachineListenerAdapter<States, Events>(){
			
			@Override
			public void transition(Transition<States, Events> transition){
				
				if(transition.getTarget().getId() == States.UNPAID){
					logger.info("订单创建,待支付");
					return;
				}
				if(transition.getSource().getId() == States.UNPAID
						&& transition.getTarget().getId() == States.WAITING_FOR_RECEIVE){
					logger.info("用户完成支付,待收货");
					return;
				}
				if(transition.getSource().getId() == States.WAITING_FOR_RECEIVE
						&& transition.getTarget().getId() == States.DONE){
					logger.info("用户已收货,订单完成");
				}
			}
		};
	}
}

4、创建应用主类来完成整个流程:


package com.lyd;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.statemachine.StateMachine;
 
@SpringBootApplication
public class Application implements CommandLineRunner{
 
	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}
	
	@Autowired
	private StateMachine<States, Events> stateMachine;
	
	@Override
	public void run(String... args){
		stateMachine.start();
		stateMachine.sendEvent(Events.PAY);
		stateMachine.sendEvent(Events.RECEIVE);
	}
}

整个状态的调度逻辑主要依靠配置方式的定义,而所有的业务逻辑操作都被定义在了状态监听器中,其实状态监听器可以实现的功能远不止上面我们所述的内容,它还有更多的事件捕获

注解监听器
对于状态监听器,Spring StateMachine还提供了优雅的注解配置实现方式,所有StateMachineListener接口中定义的事件都能通过注解的方式来进行配置实现。比如,我们可以将之前实现的状态监听器用注解配置来做进一步的简化。


package com.lyd;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.statemachine.annotation.OnTransition;
import org.springframework.statemachine.annotation.OnTransitionEnd;
import org.springframework.statemachine.annotation.OnTransitionStart;
import org.springframework.statemachine.annotation.WithStateMachine;
 
/**
 * 该配置实现了com.lyd.StateMachineConfig类中定义的状态机监听器实现。 
 */
@WithStateMachine
public class EventConfig {
 
	private Logger logger = LoggerFactory.getLogger(getClass());
	
	@OnTransition(target = "UNPAID")
	public void create(){
		logger.info("订单创建,待支付");
	}
	
	@OnTransition(source = "UNPAID", target = "WAITING_FOR_RECEIVE")
    public void pay() {
        logger.info("用户完成支付,待收货");
    }
 
    @OnTransitionStart(source = "UNPAID", target = "WAITING_FOR_RECEIVE")
    public void payStart() {
        logger.info("用户完成支付,待收货: start");
    }
 
    @OnTransitionEnd(source = "UNPAID", target = "WAITING_FOR_RECEIVE")
    public void payEnd() {
        logger.info("用户完成支付,待收货: end");
    }
    
    @OnTransition(source = "WAITING_FOR_RECEIVE", target = "DONE")
    public void receive() {
        logger.info("用户已收货,订单完成");
    }
}

状态机实现原理

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐