├── README.md ├── doc └── demo.png ├── pom.xml ├── statemachine-core ├── pom.xml └── src │ └── main │ └── java │ ├── com │ └── github │ │ └── shxz130 │ │ └── statemachine │ │ └── core │ │ ├── config │ │ ├── BaseStateMachineKey.java │ │ └── Handler.java │ │ └── fire │ │ ├── StateConfiguration.java │ │ ├── StateMachine.java │ │ ├── StateMachineConfig.java │ │ ├── StateMachineFactory.java │ │ └── TransactionContext.java │ └── package-info.java └── statemachine-demo ├── pom.xml └── src └── main └── java └── com └── github └── shxz130 └── statemachine └── demo ├── config ├── LeavePermitContextConstants.java ├── LeavePermitEvent.java ├── LeavePermitState.java ├── StatemachineInit.java ├── bean │ └── LeavePermit.java └── handler │ ├── CeoPermitHandler.java │ ├── LeaderPermitHandler.java │ ├── PermitFailHandler.java │ ├── PermitSuccessHandler.java │ └── SubmitLeavePermitHandler.java ├── main └── Main.java └── package-info.java /README.md: -------------------------------------------------------------------------------- 1 | 2 | **背景** 3 | 4 | 之前18年曾经写过一篇关于状态机的博客,链接如下: 5 | [https://www.jianshu.com/p/8def04b34b3c](https://www.jianshu.com/p/8def04b34b3c) 6 | 在楼主当初的设计过程中,已经认为是非常完美的一篇关于状态机的文章了,后续,做相关交易系统的时候,觉得该状态机还是太重,过于复杂,于是,便重新设计了一套极简状态机,为什么说是极简状态机,因为这套状态机太过于简单,只有仅仅几个类,而且,轻依赖,仅仅依赖于lombok.jar和slf4j,用于生成set,get方法和打印日志。 7 | 8 | **为什么需要状态机** 9 | 10 | 还是和上文一样,举个请假的例子,当我们需要请假的时候,首先需要领导审批,领导审批完成ceo审批,当然,并不是所有假条都能够审批完成,也有可能CEO拒绝这个假单,也可能直线领导拒绝这个假单,随着不同的审批意见,则会有不同的流程,去处理假条。 11 | 在这里,我们把假单看成业务单(可以是交易单,也可以是业务订单),状态机就是整个审批过程(审批过程的过程,审批链就是状态机),而审批意见就决定了状态机走哪条路。 12 | 13 | **举例** 14 | 15 | 我们还是拿着请假来说事,先想想我们请假需要经过的几个步骤。 16 | * 提交假条 17 | * 领导审批 18 | * ceo审批 19 | 20 | 21 | 当然,也可能是到了领导,或者ceo审批终止,请假失败。 22 | 所以我们需要一个枚举类,来定义我们需要的步骤。 23 | ```java 24 | public enum LeavePermitState { 25 | SUBMIT_PERMIT,//提交假单 26 | LEADER_PERMIT,//领导审批 27 | CEO_PERMIT,//CEO审批 28 | } 29 | ``` 30 | 知道了该找谁批假条,也得看领导或者ceo批还是不批,所以还需要审批意见,在这里用一个枚举来定义,叫做event。这里为什么会有提交假单和领导审批,因为当你写完假单之后,你就自己会去找领导审批,而非有其他人督促你去提交假单,也就意味着有些步骤是你自己去驱动,自己决定要不要往下走。对于需要外部的意见,就只能等外部意见再接着走了。 31 | ```java 32 | public enum LeavePermitEvent { 33 | SUBMIT_PERMIT,//提交假单 34 | LEADER_PERMIT,//领导审批 35 | LEADER_PERMIT_AGREE,//领导审批通过 36 | LEADER_PERMIT_DISAGREE,//领导审批不通过 37 | CEO_PERMIT_AGREE,//ceo审批通过 38 | CEO_PERMIT_DISAGREE,//ceo审批不通过 39 | } 40 | ``` 41 | 审批动作和相关审批意见都已经有了,怎么把动作和审批意见关联起来,也就是状态机刻画出来,状态机怎么知道,这个意见是到了哪个动作去处理的?先画个图: 42 | ![未命名文件 (15).png](./doc/demo.png) 43 | 解释一下: 44 | 当我们需要请假的时候,首先拿一个请假条(Event就是SUBMIT_COMMIT),然后填写相关请假信息(LeavePermitHandler),然后找领导审批(Event就是LEADER_PERMIT,意思是找领导审批),领导审批就会有两种不同意见,同意或者不同意,如果同意,则就要ceo审批,如果不同意,整个假条就失败了。ceo审批通过,则请假成功,假条才会到成功状态。怎么把这一系列动作刻画出来?在状态机里,可以在Spring上下文创建完成,加载状态机相关配置,也可以在静态方法中初始化。 45 | ```java 46 | public class StatemachineInit { 47 | 48 | //初始化状态机 49 | public static void init(){ 50 | //支持多状态机 这里以请假为例,可以支持多种 51 | StateMachineFactory.register("LEAVE_PERMIT",buildLeavePermitStateMachine()); 52 | 53 | } 54 | 55 | private static StateMachine buildLeavePermitStateMachine() { 56 | StateMachineConfig stateMachineConfig=new StateMachineConfig(); 57 | 58 | stateMachineConfig.from(LeavePermitState.SUBMIT_PERMIT)//初始状态,提交假单 59 | .permit(LeavePermitEvent.SUBMIT_PERMIT) //拿假条 60 | .handle(new SubmitLeavePermitHandler())//填假条 61 | .to(LeavePermitState.LEADER_PERMIT) //填完之后,到领导审批 62 | .build(); 63 | 64 | stateMachineConfig.from(LeavePermitState.LEADER_PERMIT) //领导审批 65 | .permit(LeavePermitEvent.LEADER_PERMIT) //待审批 66 | .handle(new LeaderPermitHandler()) //领导查阅 67 | .to(LeavePermitState.LEADER_PERMIT) //查阅完,仍旧是领导审批状态 68 | .build(); 69 | 70 | 71 | stateMachineConfig.from(LeavePermitState.LEADER_PERMIT) //领导审批 72 | .permit(LeavePermitEvent.LEADER_PERMIT_AGREE) //领导同意 73 | .handle(new CeoPermitHandler()) //领导同意之后CEO审批 74 | .to(LeavePermitState.CEO_PERMIT) //ceo审批 75 | .build(); 76 | 77 | stateMachineConfig.from(LeavePermitState.LEADER_PERMIT) //领导审批 78 | .permit(LeavePermitEvent.LEADER_PERMIT_DISAGREE) //领导不同意 79 | .handle(new PermitFailHandler()) //假条失败 80 | .build(); 81 | 82 | stateMachineConfig.from(LeavePermitState.CEO_PERMIT) //CEO审批 83 | .permit(LeavePermitEvent.CEO_PERMIT_AGREE) //ceo审批同意 84 | .handle(new PermitSuccessHandler()) //假条成功 85 | .build(); 86 | 87 | 88 | stateMachineConfig.from(LeavePermitState.CEO_PERMIT) //ceo审批 89 | .handle(new PermitFailHandler()) //ceo审批不通过 90 | .permit(LeavePermitEvent.CEO_PERMIT_DISAGREE) //假条失败 91 | .build(); 92 | 93 | return new StateMachine(stateMachineConfig); 94 | } 95 | } 96 | ``` 97 | 程序到底如何运行,才能跑起来? 98 | ```java 99 | public static void main(String[] args){ 100 | //初始化状态机 101 | StatemachineInit.init(); 102 | log.info("创建假单"); 103 | //创建上下文 104 | TransactionContext transactionContext=new TransactionContext(); 105 | transactionContext.setData(LeavePermitContextConstants.CURRENT_STATE, LeavePermitState.SUBMIT_PERMIT); 106 | //开始请假,从拿请假条开始 107 | StateMachineFactory.getStateMachine("LEAVE_PERMIT").fire(LeavePermitEvent.SUBMIT_PERMIT, transactionContext); 108 | 109 | //拿假条,填写假条之后,需要领导审批 110 | log.info("领导审批"); 111 | LeavePermit leavePermit=(LeavePermit)transactionContext.getData(LeavePermitContextConstants.LEAVE_PERMIT); 112 | TransactionContext transactionContext2=new TransactionContext(); 113 | transactionContext2.setData(LeavePermitContextConstants.LEAVE_PERMIT,leavePermit); 114 | transactionContext2.setData(LeavePermitContextConstants.CURRENT_STATE, LeavePermitState.LEADER_PERMIT); 115 | //领导审批通过,同意该假单 116 | StateMachineFactory.getStateMachine("LEAVE_PERMIT").fire(LeavePermitEvent.LEADER_PERMIT_AGREE, transactionContext2); 117 | 118 | log.info("ceo审批"); 119 | LeavePermit leavePermit2=(LeavePermit)transactionContext.getData(LeavePermitContextConstants.LEAVE_PERMIT); 120 | TransactionContext transactionContext3=new TransactionContext(); 121 | transactionContext3.setData(LeavePermitContextConstants.LEAVE_PERMIT,leavePermit2); 122 | transactionContext3.setData(LeavePermitContextConstants.CURRENT_STATE, LeavePermitState.CEO_PERMIT); 123 | 124 | //ceo审批通过 125 | StateMachineFactory.getStateMachine("LEAVE_PERMIT").fire(LeavePermitEvent.CEO_PERMIT_AGREE, transactionContext3); 126 | } 127 | ``` 128 | 有种类似开车的场景,状态机就像地图,指示牌就是Event,然后汽车是假条,当汽车走到某一个路口,会按照指示牌选择不同的路走,假条也是按照不同的Event(审批意见)在走,状态机和假条之前并没有必然关系,都是线程所有。不存在并发问题,就像汽车走在路上,然而路并和汽车没有关系,只是因为汽车上走的是路,所以状态机与业务并没有关系,而是业务跑在状态机上。 129 | 运行结果: 130 | ```txt 131 | 4:27:20.933 [main] INFO com.github.shxz130.statemachine.demo.main.Main - 创建假单 132 | 14:27:20.940 [main] INFO com.github.shxz130.statemachine.core.fire.StateMachine - [StateMachine] runing currentState=[SUBMIT_PERMIT], event=[SUBMIT_PERMIT], handle=[SubmitLeavePermitHandler], nextState=[LEADER_PERMIT] 133 | 14:27:20.944 [main] INFO com.github.shxz130.statemachine.demo.config.handler.SubmitLeavePermitHandler - [SubmitLeavePermitHandler],permit=[LeavePermit(permitNo=PERMITN, status=INIT)] 134 | 14:27:20.944 [main] INFO com.github.shxz130.statemachine.core.fire.StateMachine - [StateMachine] runing currentState=[LEADER_PERMIT], event=[LEADER_PERMIT], handle=[LeaderPermitHandler], nextState=[LEADER_PERMIT] 135 | 14:27:20.944 [main] INFO com.github.shxz130.statemachine.demo.config.handler.LeaderPermitHandler - [LeaderPermitHandler],permit=[LeavePermit(permitNo=PERMITN, status=LEADER_PERMIT)] 136 | 14:27:20.944 [main] INFO com.github.shxz130.statemachine.demo.config.handler.LeaderPermitHandler - 等待领导审批 137 | 14:27:20.944 [main] INFO com.github.shxz130.statemachine.demo.main.Main - 领导审批 138 | 14:27:20.945 [main] INFO com.github.shxz130.statemachine.core.fire.StateMachine - [StateMachine] runing currentState=[LEADER_PERMIT], event=[LEADER_PERMIT_AGREE], handle=[CeoPermitHandler], nextState=[CEO_PERMIT] 139 | 14:27:20.945 [main] INFO com.github.shxz130.statemachine.demo.config.handler.CeoPermitHandler - [CeoPermitHandler],permit=[LeavePermit(permitNo=PERMITN, status=CEO_PERMIT)] 140 | 14:27:20.945 [main] INFO com.github.shxz130.statemachine.demo.config.handler.CeoPermitHandler - 等待ceo审批 141 | 14:27:20.945 [main] INFO com.github.shxz130.statemachine.demo.main.Main - 领导审批 142 | 14:27:20.945 [main] INFO com.github.shxz130.statemachine.core.fire.StateMachine - [StateMachine] runing currentState=[CEO_PERMIT], event=[CEO_PERMIT_AGREE], handle=[PermitSuccessHandler], nextState=[null] 143 | 14:27:20.945 [main] INFO com.github.shxz130.statemachine.demo.config.handler.PermitSuccessHandler - [PermitSuccessHandler],permit=[LeavePermit(permitNo=PERMITN, status=SUCCESS)],审批意见:[{}] 144 | Disconnected from the target VM, address: '127.0.0.1:61095', transport: 'socket' 145 | ``` 146 | 这个例子写的比较粗,懂其意思即可。 147 | 感兴趣的可以看源码,我把状态机核心和demo做了分离,了解使用,仅关心demo即可,想了解原理,查看core即可。 148 | 欢迎fork交流。 149 | -------------------------------------------------------------------------------- /doc/demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shxz130/statemachine/e2376ddfdaca5893e364348328d81ae0b7818fb1/doc/demo.png -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.github.shxz130.statemachine 8 | statemachine 9 | pom 10 | 1.0-SNAPSHOT 11 | 12 | statemachine-core 13 | statemachine-demo 14 | 15 | 16 | 17 | 18 | 19 | org.projectlombok 20 | lombok 21 | 1.16.10 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /statemachine-core/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | statemachine-core 7 | com.github.shxz130.statemachine 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | 13 | 14 | org.projectlombok 15 | lombok 16 | 1.16.16 17 | 18 | 19 | 20 | org.slf4j 21 | slf4j-api 22 | 1.7.25 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /statemachine-core/src/main/java/com/github/shxz130/statemachine/core/config/BaseStateMachineKey.java: -------------------------------------------------------------------------------- 1 | package com.github.shxz130.statemachine.core.config; 2 | 3 | /** 4 | * Created by jetty on 2019/7/31. 5 | */ 6 | 7 | public class BaseStateMachineKey { 8 | 9 | public static final String CURRENT_STATE="CURRENT_STATE"; 10 | 11 | } 12 | -------------------------------------------------------------------------------- /statemachine-core/src/main/java/com/github/shxz130/statemachine/core/config/Handler.java: -------------------------------------------------------------------------------- 1 | package com.github.shxz130.statemachine.core.config; 2 | 3 | import com.github.shxz130.statemachine.core.fire.StateMachine; 4 | import com.github.shxz130.statemachine.core.fire.TransactionContext; 5 | 6 | /** 7 | * Created by jetty on 2019/7/31. 8 | */ 9 | public interface Handler { 10 | 11 | void handle(TransactionContext context, StateMachine stateMachine); 12 | } 13 | -------------------------------------------------------------------------------- /statemachine-core/src/main/java/com/github/shxz130/statemachine/core/fire/StateConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.github.shxz130.statemachine.core.fire; 2 | 3 | import lombok.Getter; 4 | 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | 8 | /** 9 | * Created by jetty on 2019/7/31. 10 | */ 11 | 12 | public class StateConfiguration { 13 | 14 | @Getter 15 | private S currentState; 16 | 17 | private Map eventHandleMap; 18 | 19 | private Map nextStateMap; 20 | 21 | public StateConfiguration(S state) { 22 | this.currentState = state; 23 | eventHandleMap = new HashMap(8); 24 | nextStateMap = new HashMap(8); 25 | } 26 | 27 | public void configEventHandle(E e,H h){ 28 | eventHandleMap.put(e,h); 29 | } 30 | 31 | public void configEventNextState(E e,S s){ 32 | nextStateMap.put(e,s); 33 | } 34 | 35 | public H getHandle(E e){ 36 | return eventHandleMap.get(e); 37 | } 38 | 39 | public S getNextState(E e){ 40 | return nextStateMap.get(e); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /statemachine-core/src/main/java/com/github/shxz130/statemachine/core/fire/StateMachine.java: -------------------------------------------------------------------------------- 1 | package com.github.shxz130.statemachine.core.fire; 2 | 3 | import com.github.shxz130.statemachine.core.config.BaseStateMachineKey; 4 | import com.github.shxz130.statemachine.core.config.Handler; 5 | import lombok.extern.slf4j.Slf4j; 6 | 7 | /** 8 | * Created by jetty on 2019/7/31. 9 | */ 10 | @Slf4j 11 | public class StateMachine { 12 | 13 | private final StateMachineConfig stateMachineConfig; 14 | 15 | 16 | public StateMachine( StateMachineConfig config) { 17 | this.stateMachineConfig = config; 18 | } 19 | 20 | /** 21 | * 触发 22 | * 23 | * @param event 触发器 24 | * @param context 上下文 25 | */ 26 | public void fire(E event, TransactionContext context) { 27 | S mainStateEnum=(S)context.getData(BaseStateMachineKey.CURRENT_STATE); 28 | if(null==mainStateEnum){ 29 | throw new RuntimeException("未找到下一个状态,状态机无法继续"); 30 | } 31 | H handle=stateMachineConfig.getHandle(mainStateEnum, event); 32 | if(handle==null){ 33 | throw new RuntimeException(String.format("状态和指令不匹配,state=[%s],event=[%s]",mainStateEnum,event)); 34 | } 35 | S nextState=stateMachineConfig.getNextState(mainStateEnum, event); 36 | context.setData(BaseStateMachineKey.CURRENT_STATE,nextState); 37 | log.info("[StateMachine] runing currentState=[{}], event=[{}], handle=[{}], nextState=[{}]",mainStateEnum,event,handle.getClass().getSimpleName(),nextState); 38 | handle.handle(context,this); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /statemachine-core/src/main/java/com/github/shxz130/statemachine/core/fire/StateMachineConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.shxz130.statemachine.core.fire; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | /** 7 | * Created by jetty on 2019/7/31. 8 | */ 9 | public class StateMachineConfig { 10 | 11 | private S tempCurrentState; 12 | private E tempEvent; 13 | private H tempHandler; 14 | private S tempNextState; 15 | 16 | private final Map> stateConfigurationMap = new HashMap>(8); 17 | 18 | public StateMachineConfig from(S s){ 19 | this.tempCurrentState=s; 20 | return this; 21 | } 22 | public StateMachineConfig permit(E e){ 23 | this.tempEvent=e; 24 | return this; 25 | } 26 | 27 | public StateMachineConfig handle(H h){ 28 | this.tempHandler=h; 29 | return this; 30 | } 31 | 32 | 33 | public StateMachineConfig to(S s){ 34 | this.tempNextState=s; 35 | return this; 36 | } 37 | 38 | public void build(){ 39 | StateConfiguration stateConfiguration= createOrGetStateConfiguration(tempCurrentState); 40 | stateConfiguration.configEventHandle(tempEvent,tempHandler); 41 | stateConfiguration.configEventNextState(tempEvent,tempNextState); 42 | this.tempCurrentState=null; 43 | this.tempEvent=null; 44 | this.tempHandler=null; 45 | this.tempNextState=null; 46 | } 47 | 48 | 49 | private StateConfiguration createOrGetStateConfiguration(S s){ 50 | if(stateConfigurationMap.get(s)==null){ 51 | StateConfiguration stateConfiguration=new StateConfiguration(s); 52 | stateConfigurationMap.put(s,stateConfiguration); 53 | } 54 | return stateConfigurationMap.get(s); 55 | } 56 | 57 | public H getHandle(S s,E e){ 58 | StateConfiguration stateConfiguration=stateConfigurationMap.get(s); 59 | if(stateConfiguration==null){ 60 | return null; 61 | } 62 | return (H)stateConfiguration.getHandle(e); 63 | } 64 | 65 | public S getNextState(S s,E e){ 66 | return stateConfigurationMap.get(s)==null?null: stateConfigurationMap.get(s).getNextState(e); 67 | } 68 | } -------------------------------------------------------------------------------- /statemachine-core/src/main/java/com/github/shxz130/statemachine/core/fire/StateMachineFactory.java: -------------------------------------------------------------------------------- 1 | package com.github.shxz130.statemachine.core.fire; 2 | 3 | import com.github.shxz130.statemachine.core.config.Handler; 4 | 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | 8 | /** 9 | * Created by jetty on 2019/7/31. 10 | */ 11 | public final class StateMachineFactory { 12 | 13 | private static Map> stateMachineMap = new HashMap>(); 14 | 15 | 16 | private StateMachineFactory() { 17 | } 18 | 19 | 20 | public static void register(String key,StateMachine stateMachine){ 21 | stateMachineMap.put(key,stateMachine); 22 | } 23 | 24 | public static StateMachine getStateMachine(String key){ 25 | return stateMachineMap.get(key); 26 | } 27 | } -------------------------------------------------------------------------------- /statemachine-core/src/main/java/com/github/shxz130/statemachine/core/fire/TransactionContext.java: -------------------------------------------------------------------------------- 1 | package com.github.shxz130.statemachine.core.fire; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | /** 7 | * Created by jetty on 2019/7/31. 8 | */ 9 | public class TransactionContext { 10 | 11 | private Map dataMap; 12 | 13 | public TransactionContext() { 14 | this.dataMap = new HashMap(); 15 | } 16 | 17 | public Object getData(String key){ 18 | return dataMap.get(key); 19 | } 20 | 21 | public Object setData(String key,Object value){ 22 | return dataMap.put(key,value); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /statemachine-core/src/main/java/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by jetty on 2019/7/31. 3 | */ 4 | -------------------------------------------------------------------------------- /statemachine-demo/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | statemachine 7 | com.github.shxz130.statemachine 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | statemachine-demo 13 | 14 | 15 | 16 | 17 | ch.qos.logback 18 | logback-classic 19 | 1.2.3 20 | 21 | 22 | 23 | statemachine-core 24 | com.github.shxz130.statemachine 25 | 1.0-SNAPSHOT 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /statemachine-demo/src/main/java/com/github/shxz130/statemachine/demo/config/LeavePermitContextConstants.java: -------------------------------------------------------------------------------- 1 | package com.github.shxz130.statemachine.demo.config; 2 | 3 | import com.github.shxz130.statemachine.core.config.BaseStateMachineKey; 4 | 5 | /** 6 | * Created by jetty on 2019/7/31. 7 | */ 8 | public final class LeavePermitContextConstants extends BaseStateMachineKey { 9 | 10 | public static final String LEAVE_PERMIT="LEAVE_PERMIT"; 11 | 12 | public static final String LEADER_PERMIT_SUGGESTION="LEADER_PERMIT_SUGGESTION"; 13 | 14 | public static final String CEO_PERMIT_SUGGESTION="CEO_PERMIT_SUGGESTION"; 15 | 16 | } 17 | -------------------------------------------------------------------------------- /statemachine-demo/src/main/java/com/github/shxz130/statemachine/demo/config/LeavePermitEvent.java: -------------------------------------------------------------------------------- 1 | package com.github.shxz130.statemachine.demo.config; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * Created by jetty on 2019/7/31. 7 | */ 8 | public enum LeavePermitEvent { 9 | SUBMIT_PERMIT,//提交假单 10 | LEADER_PERMIT,//领导审批 11 | LEADER_PERMIT_AGREE,//领导审批通过 12 | LEADER_PERMIT_DISAGREE,//领导审批不通过 13 | CEO_PERMIT_AGREE,//ceo审批通过 14 | CEO_PERMIT_DISAGREE,//ceo审批不通过 15 | } 16 | -------------------------------------------------------------------------------- /statemachine-demo/src/main/java/com/github/shxz130/statemachine/demo/config/LeavePermitState.java: -------------------------------------------------------------------------------- 1 | package com.github.shxz130.statemachine.demo.config; 2 | 3 | /** 4 | * Created by jetty on 2019/7/31. 5 | */ 6 | public enum LeavePermitState { 7 | 8 | SUBMIT_PERMIT,//提交假单 9 | LEADER_PERMIT,//领导审批 10 | CEO_PERMIT,//CEO审批 11 | 12 | } 13 | -------------------------------------------------------------------------------- /statemachine-demo/src/main/java/com/github/shxz130/statemachine/demo/config/StatemachineInit.java: -------------------------------------------------------------------------------- 1 | package com.github.shxz130.statemachine.demo.config; 2 | 3 | import com.github.shxz130.statemachine.core.config.Handler; 4 | import com.github.shxz130.statemachine.core.fire.StateMachine; 5 | import com.github.shxz130.statemachine.core.fire.StateMachineConfig; 6 | import com.github.shxz130.statemachine.core.fire.StateMachineFactory; 7 | import com.github.shxz130.statemachine.demo.config.handler.*; 8 | 9 | /** 10 | * Created by jetty on 2019/7/31. 11 | */ 12 | public class StatemachineInit { 13 | 14 | //初始化状态机 15 | public static void init(){ 16 | //支持多状态机 这里以请假为例,可以支持多种 17 | StateMachineFactory.register("LEAVE_PERMIT",buildLeavePermitStateMachine()); 18 | 19 | } 20 | 21 | private static StateMachine buildLeavePermitStateMachine() { 22 | StateMachineConfig stateMachineConfig=new StateMachineConfig(); 23 | 24 | stateMachineConfig.from(LeavePermitState.SUBMIT_PERMIT)//初始状态,提交假单 25 | .permit(LeavePermitEvent.SUBMIT_PERMIT) //拿假条 26 | .handle(new SubmitLeavePermitHandler())//填假条 27 | .to(LeavePermitState.LEADER_PERMIT) //填完之后,到领导审批 28 | .build(); 29 | 30 | stateMachineConfig.from(LeavePermitState.LEADER_PERMIT) //领导审批 31 | .permit(LeavePermitEvent.LEADER_PERMIT) //待审批 32 | .handle(new LeaderPermitHandler()) //领导查阅 33 | .to(LeavePermitState.LEADER_PERMIT) //查阅完,仍旧是领导审批状态 34 | .build(); 35 | 36 | 37 | stateMachineConfig.from(LeavePermitState.LEADER_PERMIT) //领导审批 38 | .permit(LeavePermitEvent.LEADER_PERMIT_AGREE) //领导同意 39 | .handle(new CeoPermitHandler()) //领导同意之后CEO审批 40 | .to(LeavePermitState.CEO_PERMIT) //ceo审批 41 | .build(); 42 | 43 | stateMachineConfig.from(LeavePermitState.LEADER_PERMIT) //领导审批 44 | .permit(LeavePermitEvent.LEADER_PERMIT_DISAGREE) //领导不同意 45 | .handle(new PermitFailHandler()) //假条失败 46 | .build(); 47 | 48 | stateMachineConfig.from(LeavePermitState.CEO_PERMIT) //CEO审批 49 | .permit(LeavePermitEvent.CEO_PERMIT_AGREE) //ceo审批同意 50 | .handle(new PermitSuccessHandler()) //假条成功 51 | .build(); 52 | 53 | 54 | stateMachineConfig.from(LeavePermitState.CEO_PERMIT) //ceo审批 55 | .handle(new PermitFailHandler()) //ceo审批不通过 56 | .permit(LeavePermitEvent.CEO_PERMIT_DISAGREE) //假条失败 57 | .build(); 58 | 59 | return new StateMachine(stateMachineConfig); 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /statemachine-demo/src/main/java/com/github/shxz130/statemachine/demo/config/bean/LeavePermit.java: -------------------------------------------------------------------------------- 1 | package com.github.shxz130.statemachine.demo.config.bean; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * Created by jetty on 2019/7/31. 7 | */ 8 | @Data 9 | public class LeavePermit { 10 | 11 | private String permitNo; 12 | 13 | private String status; 14 | } 15 | -------------------------------------------------------------------------------- /statemachine-demo/src/main/java/com/github/shxz130/statemachine/demo/config/handler/CeoPermitHandler.java: -------------------------------------------------------------------------------- 1 | package com.github.shxz130.statemachine.demo.config.handler; 2 | 3 | import com.github.shxz130.statemachine.core.config.Handler; 4 | import com.github.shxz130.statemachine.core.fire.StateMachine; 5 | import com.github.shxz130.statemachine.core.fire.TransactionContext; 6 | import com.github.shxz130.statemachine.demo.config.LeavePermitContextConstants; 7 | import com.github.shxz130.statemachine.demo.config.LeavePermitEvent; 8 | import com.github.shxz130.statemachine.demo.config.bean.LeavePermit; 9 | import lombok.extern.slf4j.Slf4j; 10 | 11 | /** 12 | * Created by jetty on 2019/7/31. 13 | */ 14 | @Slf4j 15 | public class CeoPermitHandler implements Handler{ 16 | 17 | public void handle(TransactionContext context, StateMachine stateMachine) { 18 | LeavePermit leavePermit=(LeavePermit)context.getData(LeavePermitContextConstants.LEAVE_PERMIT); 19 | leavePermit.setStatus("CEO_PERMIT"); 20 | String ceoSuggestion=(String)context.getData(LeavePermitContextConstants.CEO_PERMIT_SUGGESTION); 21 | log.info("[{}],permit=[{}]", this.getClass().getSimpleName(),leavePermit); 22 | if(ceoSuggestion==null){ 23 | log.info("等待ceo审批"); 24 | return; 25 | } 26 | 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /statemachine-demo/src/main/java/com/github/shxz130/statemachine/demo/config/handler/LeaderPermitHandler.java: -------------------------------------------------------------------------------- 1 | package com.github.shxz130.statemachine.demo.config.handler; 2 | 3 | import com.github.shxz130.statemachine.core.config.Handler; 4 | import com.github.shxz130.statemachine.core.fire.StateMachine; 5 | import com.github.shxz130.statemachine.core.fire.TransactionContext; 6 | import com.github.shxz130.statemachine.demo.config.LeavePermitContextConstants; 7 | import com.github.shxz130.statemachine.demo.config.LeavePermitEvent; 8 | import com.github.shxz130.statemachine.demo.config.bean.LeavePermit; 9 | import lombok.extern.slf4j.Slf4j; 10 | 11 | /** 12 | * Created by jetty on 2019/7/31. 13 | */ 14 | @Slf4j 15 | public class LeaderPermitHandler implements Handler{ 16 | 17 | public void handle(TransactionContext context, StateMachine stateMachine) { 18 | LeavePermit leavePermit=(LeavePermit)context.getData(LeavePermitContextConstants.LEAVE_PERMIT); 19 | leavePermit.setStatus("LEADER_PERMIT"); 20 | log.info("[{}],permit=[{}]", this.getClass().getSimpleName(),leavePermit); 21 | String leaderSuggestion=(String)context.getData(LeavePermitContextConstants.LEADER_PERMIT_SUGGESTION); 22 | if(leaderSuggestion==null){ 23 | log.info("等待领导审批"); 24 | return; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /statemachine-demo/src/main/java/com/github/shxz130/statemachine/demo/config/handler/PermitFailHandler.java: -------------------------------------------------------------------------------- 1 | package com.github.shxz130.statemachine.demo.config.handler; 2 | 3 | import com.github.shxz130.statemachine.core.config.Handler; 4 | import com.github.shxz130.statemachine.core.fire.StateMachine; 5 | import com.github.shxz130.statemachine.core.fire.TransactionContext; 6 | import com.github.shxz130.statemachine.demo.config.LeavePermitContextConstants; 7 | import com.github.shxz130.statemachine.demo.config.LeavePermitEvent; 8 | import com.github.shxz130.statemachine.demo.config.bean.LeavePermit; 9 | import lombok.extern.slf4j.Slf4j; 10 | 11 | /** 12 | * Created by jetty on 2019/7/31. 13 | */ 14 | @Slf4j 15 | public class PermitFailHandler implements Handler{ 16 | 17 | public void handle(TransactionContext context, StateMachine stateMachine) { 18 | LeavePermit leavePermit=(LeavePermit)context.getData(LeavePermitContextConstants.LEAVE_PERMIT); 19 | leavePermit.setStatus("FAIL"); 20 | log.info("[{}],permit=[{}],审批意见:[{}]", this.getClass().getSimpleName(), leavePermit); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /statemachine-demo/src/main/java/com/github/shxz130/statemachine/demo/config/handler/PermitSuccessHandler.java: -------------------------------------------------------------------------------- 1 | package com.github.shxz130.statemachine.demo.config.handler; 2 | 3 | import com.github.shxz130.statemachine.core.config.Handler; 4 | import com.github.shxz130.statemachine.core.fire.StateMachine; 5 | import com.github.shxz130.statemachine.core.fire.TransactionContext; 6 | import com.github.shxz130.statemachine.demo.config.LeavePermitContextConstants; 7 | import com.github.shxz130.statemachine.demo.config.bean.LeavePermit; 8 | import lombok.extern.slf4j.Slf4j; 9 | 10 | /** 11 | * Created by jetty on 2019/7/31. 12 | */ 13 | @Slf4j 14 | public class PermitSuccessHandler implements Handler{ 15 | 16 | public void handle(TransactionContext context, StateMachine stateMachine) { 17 | LeavePermit leavePermit=(LeavePermit)context.getData(LeavePermitContextConstants.LEAVE_PERMIT); 18 | leavePermit.setStatus("SUCCESS"); 19 | log.info("[{}],permit=[{}],审批意见:[{}]", this.getClass().getSimpleName(), leavePermit); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /statemachine-demo/src/main/java/com/github/shxz130/statemachine/demo/config/handler/SubmitLeavePermitHandler.java: -------------------------------------------------------------------------------- 1 | package com.github.shxz130.statemachine.demo.config.handler; 2 | 3 | import com.github.shxz130.statemachine.core.config.Handler; 4 | import com.github.shxz130.statemachine.core.fire.StateMachine; 5 | import com.github.shxz130.statemachine.core.fire.TransactionContext; 6 | import com.github.shxz130.statemachine.demo.config.LeavePermitContextConstants; 7 | import com.github.shxz130.statemachine.demo.config.LeavePermitEvent; 8 | import com.github.shxz130.statemachine.demo.config.bean.LeavePermit; 9 | import lombok.extern.slf4j.Slf4j; 10 | 11 | /** 12 | * Created by jetty on 2019/7/31. 13 | */ 14 | @Slf4j 15 | public class SubmitLeavePermitHandler implements Handler{ 16 | 17 | public void handle(TransactionContext context, StateMachine stateMachine) { 18 | LeavePermit leavePermit=new LeavePermit(); 19 | leavePermit.setPermitNo("PERMITN"); 20 | leavePermit.setStatus("INIT");//设置为初始状态 21 | log.info("[{}],permit=[{}]", this.getClass().getSimpleName(), leavePermit); 22 | context.setData(LeavePermitContextConstants.LEAVE_PERMIT, leavePermit); 23 | stateMachine.fire(LeavePermitEvent.LEADER_PERMIT,context); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /statemachine-demo/src/main/java/com/github/shxz130/statemachine/demo/main/Main.java: -------------------------------------------------------------------------------- 1 | package com.github.shxz130.statemachine.demo.main; 2 | 3 | import com.github.shxz130.statemachine.core.fire.StateMachineFactory; 4 | import com.github.shxz130.statemachine.core.fire.TransactionContext; 5 | import com.github.shxz130.statemachine.demo.config.LeavePermitContextConstants; 6 | import com.github.shxz130.statemachine.demo.config.LeavePermitEvent; 7 | import com.github.shxz130.statemachine.demo.config.LeavePermitState; 8 | import com.github.shxz130.statemachine.demo.config.StatemachineInit; 9 | import com.github.shxz130.statemachine.demo.config.bean.LeavePermit; 10 | import lombok.extern.slf4j.Slf4j; 11 | 12 | /** 13 | * Created by jetty on 2019/7/31. 14 | */ 15 | @Slf4j 16 | public class Main { 17 | 18 | public static void main(String[] args){ 19 | StatemachineInit.init(); 20 | 21 | log.info("创建假单"); 22 | TransactionContext transactionContext=new TransactionContext(); 23 | transactionContext.setData(LeavePermitContextConstants.CURRENT_STATE, LeavePermitState.SUBMIT_PERMIT); 24 | StateMachineFactory.getStateMachine("LEAVE_PERMIT").fire(LeavePermitEvent.SUBMIT_PERMIT, transactionContext); 25 | 26 | 27 | log.info("领导审批"); 28 | LeavePermit leavePermit=(LeavePermit)transactionContext.getData(LeavePermitContextConstants.LEAVE_PERMIT); 29 | TransactionContext transactionContext2=new TransactionContext(); 30 | transactionContext2.setData(LeavePermitContextConstants.LEAVE_PERMIT,leavePermit); 31 | transactionContext2.setData(LeavePermitContextConstants.CURRENT_STATE, LeavePermitState.LEADER_PERMIT); 32 | StateMachineFactory.getStateMachine("LEAVE_PERMIT").fire(LeavePermitEvent.LEADER_PERMIT_AGREE, transactionContext2); 33 | 34 | log.info("ceo审批"); 35 | LeavePermit leavePermit2=(LeavePermit)transactionContext.getData(LeavePermitContextConstants.LEAVE_PERMIT); 36 | TransactionContext transactionContext3=new TransactionContext(); 37 | transactionContext3.setData(LeavePermitContextConstants.LEAVE_PERMIT,leavePermit2); 38 | transactionContext3.setData(LeavePermitContextConstants.CURRENT_STATE, LeavePermitState.CEO_PERMIT); 39 | StateMachineFactory.getStateMachine("LEAVE_PERMIT").fire(LeavePermitEvent.CEO_PERMIT_AGREE, transactionContext3); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /statemachine-demo/src/main/java/com/github/shxz130/statemachine/demo/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by jetty on 2019/7/31. 3 | */ 4 | package com.github.shxz130.statemachine.demo; --------------------------------------------------------------------------------