ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

大白话说Java设计模式-33-状态模式(源码剖析篇)

大白话说Java设计模式-33-状态模式(源码剖析篇) **大厂规范**Java项目工具类 — [05_文本文件读取工具类Java企业级代码](https://download.csdn.net/download/horizon90/93427142)大白话说Java设计模式-33-状态模式源码剖析篇JDK / Spring 中的状态实现一句话本质状态在源码里不是行为随状态变的形象化而是状态对象 转换规则 触发器三件套的工业级架构。️ 标签状态模式 / Thread.State / StateMachine / TCP 适合中高级后端 / 想读懂主流框架源码的工程师目录一、为什么读状态源码一张地图先看清二、JDK 源码剖析Thread.State 线程状态三、Spring 源码剖析StateMachine 状态机四、Spring 源码剖析StateMachine 转换规则五、TCP 协议状态机分析六、为什么框架作者这么设计七、借鉴到我们项目3 个抄作业实践八、本篇小结 下一模式预告一、为什么读状态源码一张地图先看清状态模式在 JDK 和 Spring 里出现得最经典——Thread.State/StateMachine/ TCP 协议都是状态思想。源码地图类别框架 / 中间件状态机状态数JDKjava.langThread.State6 种SpringstatemachineStateMachine任意TCP网络协议TCP 状态机11 种工作流Activiti工作流引擎任意业务自定义订单状态机6 种我们按Thread.State → StateMachine → TCP的顺序来剖析。二、JDK 源码剖析Thread.State 线程状态2.1Thread.State线程状态枚举源码位置OpenJDK 17src/java.base/share/classes/java/lang/Thread.java核心源码/** * ✅ 线程状态枚举 */publicenumState{/** * 尚未启动 */NEW,/** * 在 JVM 中运行 */RUNNABLE,/** * 阻塞等待 monitor 锁 */BLOCKED,/** * 无限期等待 */WAITING,/** * 限时等待 */TIMED_WAITING,/** * 终止 */TERMINATED;}关键点状态含义NEW新建未启动RUNNABLE可运行BLOCKED阻塞WAITING无限等待TIMED_WAITING限时等待TERMINATED终止2.2 线程状态转换图NEW → RUNNABLE → BLOCKED → RUNNABLE ↓ WAITING → RUNNABLE ↓ TIMED_WAITING → RUNNABLE ↓ TERMINATED2.3 完整线程状态实现核心源码简化版/** * ✅ Thread 状态管理 */publicclassThreadimplementsRunnable{/** * ✅ 当前状态 */privatevolatileintthreadStatus0;publicStategetState(){returnthreadState;// JVM 返回}/** * 启动线程 */publicvoidstart(){// NEW → RUNNABLE}/** * 等待 */publicvoidjoin()throwsInterruptedException{// RUNNABLE → WAITING}/** * 休眠 */publicstaticvoidsleep(longmillis)throwsInterruptedException{// RUNNABLE → TIMED_WAITING}}关键点关键点解释threadStatus线程状态JVM 维护getState()获取当前状态状态转换由 JVM 内部管理2.4 线程生命周期调用链thread.start() ↓ NEW → RUNNABLE thread.run() 执行 ↓ synchronized 失败 ↓ RUNNABLE → BLOCKED 获得锁 ↓ BLOCKED → RUNNABLE thread.join() ↓ RUNNABLE → WAITING 其他线程 notify ↓ WAITING → RUNNABLE 执行完 ↓ 任意 → TERMINATED2.5Thread.State的作者选择设计点选择原因枚举6 种有限JVM 维护C 实现性能公开方法getState()简单不可变枚举线程安全三、Spring 源码剖析StateMachine 状态机3.1StateMachine状态机接口源码位置Spring Statemachine 4.0.xspring-statemachine-core/src/main/java/org/springframework/statemachine/StateMachine.java核心源码/** * ✅ 状态机接口 */publicinterfaceStateMachineS,Eextends...{/** * ✅ 发事件触发状态转换 */booleansendEvent(MessageEevent);/** * 发事件泛型 */booleansendEvent(Eevent);/** * 获取当前状态 */SetStateS,EgetState();/** * 启动状态机 */voidstart();/** * 停止状态机 */voidstop();}关键点关键点解释S状态类型E事件类型sendEvent()触发状态转换getState()获取当前状态3.2StateMachineState状态核心源码/** * ✅ 状态 */publicinterfaceStateS,EextendsRegionS,E{/** * 获取状态 ID */SgetId();}3.3Transition状态转换核心源码/** * ✅ 状态转换 */publicinterfaceTransitionS,E{/** * 源状态 */StateS,EgetSource();/** * 目标状态 */StateS,EgetTarget();/** * 触发事件 */EgetEvent();/** * 守卫转换条件 */GuardS,EgetGuard();/** * 动作 */ActionS,EgetAction();}关键点关键点解释source源状态target目标状态event触发事件guard守卫条件action动作副作用3.4StateMachineTransitionConfigurer转换配置核心源码简化版/** * ✅ 状态机配置 */publicabstractclassStateMachineConfigurerAdapterS,EimplementsStateMachineConfigurerS,E{Overridepublicvoidconfigure(StateMachineStateConfigurerS,Estates)throwsException{// 子类覆盖配置状态}Overridepublicvoidconfigure(StateMachineTransitionConfigurerS,Etransitions)throwsException{// 子类覆盖配置转换}}业务配置/** * ✅ 业务状态机配置 */ConfigurationEnableStateMachinepublicclassOrderStateMachineConfigextendsStateMachineConfigurerAdapterString,String{Overridepublicvoidconfigure(StateMachineStateConfigurerString,Stringstates)throwsException{states.withStates().initial(PENDING_PAY).state(PAID).state(SHIPPED).state(COMPLETED).state(CANCELLED).state(REFUNDING).end(COMPLETED).end(CANCELLED).end(REFUNDED);}Overridepublicvoidconfigure(StateMachineTransitionConfigurerString,Stringtransitions)throwsException{transitions.withExternal().source(PENDING_PAY).target(PAID).event(PAY).action(payAction()).and().withExternal().source(PAID).target(SHIPPED).event(SHIP).and().withExternal().source(SHIPPED).target(COMPLETED).event(COMPLETE).and().withExternal().source(PENDING_PAY).target(CANCELLED).event(CANCEL).and().withExternal().source(PAID).target(REFUNDING).event(REFUND);}publicActionString,StringpayAction(){returncontext-{// ✅ 状态转换时执行log.info(【订单】支付完成);};}}四、Spring 源码剖析StateMachine 转换规则4.1StateMachineStateAccessor状态访问器核心源码/** * ✅ 状态访问器 */publicinterfaceStateMachineStateAccessorS,E{/** * 获取当前状态 */SetStateS,EgetState();/** * 接受状态 */booleansetState(StateS,Estate);}4.2TransitionComparator转换比较器核心源码/** * ✅ 转换比较器决定哪个转换先执行 */publicclassTransitionComparatorimplementsComparatorTransition?extendsEnum?,?extendsEnum?{Overridepublicintcompare(Transition?,?o1,Transition?,?o2){// 1️⃣ 内部转换 外部转换// 2️⃣ 本地转换 外部转换// 3️⃣ 按声明顺序return0;}}4.3 完整状态机调用链orderStateMachine.sendEvent(PAY) ↓ StateMachineEngine.processEvent() ↓ 1. 找所有匹配 (statePAID, eventPAY) 的转换 2. 比较器排序 3. 检查 Guard 4. 执行 Action 5. 更新状态 6. 触发 StateChangedEvent4.4 状态机持久化/** * ✅ 状态机持久化 */publicinterfaceStateMachinePersistS,E,T{/** * 写入状态 */voidwrite(StateMachineContextS,Econtext,TcontextObj);/** * 读取状态 */StateMachineContextS,Eread(TcontextObj);}使用/** * 持久化到 Redis */publicclassRedisStateMachinePersistimplementsStateMachinePersistString,String,String{Overridepublicvoidwrite(StateMachineContextString,Stringcontext,Stringid){redisTemplate.opsForValue().set(order:sm:id,context.getState().iterator().next().getId());}OverridepublicStateMachineContextString,Stringread(Stringid){StringstateredisTemplate.opsForValue().get(order:sm:id);returnnewDefaultStateMachineContext(state,null,null,null);}}4.5StateMachine的作者选择设计点选择原因泛型S, E任意状态/事件转换规则Transition灵活守卫Guard条件判断动作Action副作用持久化Persist状态恢复五、TCP 协议状态机分析5.1 TCP 状态机概览TCP 协议是经典的状态机实现11 种状态LISTEN 监听 SYN_SENT 发送 SYN SYN_RECEIVED 收到 SYN ESTABLISHED 已连接 FIN_WAIT_1 等待 FIN-1 FIN_WAIT_2 等待 FIN-2 CLOSE_WAIT 等待关闭 CLOSING 正在关闭 LAST_ACK 最后确认 TIME_WAIT 时间等待 CLOSED 已关闭5.2 三次握手状态转换客户端 服务端 CLOSED LISTEN SYN_SENT ──SYN── SYN_RECEIVED ──SYNACK── ESTABLISHED ──ACK── ESTABLISHED5.3 四次挥手状态转换客户端 服务端 ESTABLISHED ──FIN── CLOSE_WAIT FIN_WAIT_1 ──ACK── CLOSE_WAIT FIN_WAIT_2 ──ACK── LAST_ACK ──FIN── LAST_ACK TIME_WAIT ──ACK── CLOSED 超时 CLOSED5.4 TCP 状态机源码简化Linux 内核 TCP 状态C 代码/** * TCP 状态枚举 */enumtcp_state{TCP_ESTABLISHED1,TCP_SYN_SENT,TCP_SYN_RECV,TCP_FIN_WAIT1,TCP_FIN_WAIT2,TCP_TIME_WAIT,TCP_CLOSE,TCP_CLOSE_WAIT,TCP_LAST_ACK,TCP_LISTEN,TCP_CLOSING};关键点关键点解释11 种状态复杂状态转换由协议规定操作系统维护应用层通过 socket 调5.5 TCP 状态机的作者选择设计点选择原因严格状态机11 种协议规定内核维护OS性能标准化RFC 793通用六、为什么框架作者这么设计读源码看的是实现悟的是设计哲学。6.1 框架作者选状态模式的 4 个核心考虑序号考虑举例①行为随状态变订单/线程/TCP②状态转换规则状态机定义③消除 if-else业务清晰④状态可独立测试单元测试6.2 状态 vs 状态机源码里怎么选场景选哪个原因简单行为变化状态模式简洁复杂转换规则状态机可视化业务流程状态机灵活协议状态机标准6.3 框架作者不选状态模式的 3 种情况序号场景原因①状态少switch 够用②状态之间无转换不用状态③业务极简过度设计6.4 状态在企业级应用的 3 种典型用法用法 1订单状态机 6 种状态 转换规则 → Spring StateMachine 用法 2业务流程 多步流程 → 自定义状态机 用法 3审批流 提交/审批/拒绝 → 状态机七、借鉴到我们项目3 个抄作业实践7.1 实践 1退款状态机场景大白商城退款流程申请→审核→退款中→完成/拒绝。完整实现/** * 借鉴 Spring StateMachine退款状态机 */publicinterfaceRefundState{voidapply(Refundrefund);voidapprove(Refundrefund);voidreject(Refundrefund);voidcomplete(Refundrefund);StringgetStateName();}ComponentpublicclassRefundApplyingStateimplementsRefundState{Overridepublicvoidapprove(Refundrefund){refund.setState(newRefundApprovingState());}Overridepublicvoidreject(Refundrefund){refund.setState(newRefundRejectedState());}OverridepublicStringgetStateName(){returnAPPLYING;}}7.2 实践 2工作流引擎场景大白商城请假流程提交→主管审批→HR审批→完成。完整实现/** * 借鉴 Spring StateMachine工作流 */publicclassWorkflowEngine{/** * 状态转换规则 */privatestaticfinalMapString,MapString,StringRULESnewHashMap();static{// 提交 → 主管审批RULES.computeIfAbsent(SUBMITTED,k-newHashMap()).put(MANAGER_APPROVE,MANAGER_APPROVED);// 主管审批 → HR 审批RULES.computeIfAbsent(MANAGER_APPROVED,k-newHashMap()).put(HR_APPROVE,HR_APPROVED);// HR 审批 → 完成RULES.computeIfAbsent(HR_APPROVED,k-newHashMap()).put(COMPLETE,COMPLETED);}/** * 触发事件 */publicbooleanfire(StringcurrentState,Stringevent){MapString,StringmapRULES.get(currentState);if(mapnull)returnfalse;StringnextStatemap.get(event);returnnextState!null;}}7.3 实践 3游戏角色状态场景游戏角色站立/跑步/攻击/死亡。完整实现/** * 借鉴 Thread.State游戏角色状态 */publicclassGameCharacter{privateStringstateSTANDING;publicvoidmove(){if(STANDING.equals(state)||RUNNING.equals(state)){stateRUNNING;}else{log.warn(当前状态不能移动: {},state);}}publicvoidattack(){if(RUNNING.equals(state)||STANDING.equals(state)){stateATTACKING;}}publicvoiddie(){stateDEAD;}}收益优化点效果退款状态机6 个状态可独立测试工作流引擎通用规则引擎游戏角色状态清晰八、本篇小结 下一模式预告8.1 本篇小结5 个核心要点JDK Thread.State6 种状态JVM 维护。Spring StateMachineEnableStateMachine Transition 规则。Spring 转换规则Guard Action 持久化。TCP 状态机11 种状态 RFC 793 标准。借鉴价值退款 / 工作流 / 游戏角色任何行为随状态变都用状态。8.2 一句话总结状态在源码里不是行为随状态变的形象化而是状态对象 转换规则 触发器三件套的工业级架构。Thread.State 6 种线程状态StateMachine 任意状态转换TCP 11 种协议状态。学状态先学 Thread.State 和 Spring StateMachine。8.3 知识脑图状态源码剖析 ├── JDK │ ├── Thread.State6 种 │ └── Thread.getState() ├── Spring │ ├── StateMachine │ │ ├── sendEvent() │ │ ├── getState() │ │ └── start/stop │ ├── State │ ├── Transitionsource/target/event/guard/action │ ├── StateMachineConfigurerAdapter │ └── StateMachinePersist持久化 ├── TCP │ ├── 11 种状态 │ ├── 三次握手 │ └── 四次挥手 └── 借鉴价值 ├── 退款状态机 ├── 工作流引擎 └── 游戏角色状态8.4 下一模式预告第 34 篇【命令模式 - 业务实战篇】大白商城订单撤销/重做的操作封装下一篇我们会实战命令模式回答 4 个问题订单撤销 / 重做怎么实现命令 vs 策略 / 责任链怎么区分JDK 的Runnable怎么用命令模式SpringTransactional怎么用命令模式并附完整的订单命令实战代码含命令 调用者 接收者 单元测试可直接复制到 IDEA 跑。觉得对您有帮助麻烦点点关注啦您的关注是我创作的最大动力~
返回列表