Spring State Machine:它是什么,您需要它吗?

状态机是基于有限状态的计算模型 ,正如Wikipedia非常明确地说的那样。 通常,工作流会与状态一起使用,这意味着您不能仅从任何状态进入任何其他状态:应遵循一些规则。 这些状态之间的转换受规则限制。

Spring框架具有一个称为Spring State Machine的完整库 。 它是该概念的实现,旨在为已经使用Spring框架的开发人员简化状态机逻辑的开发。

让我们看看它是如何工作的。

首先,我们需要一个Spring Boot应用程序,该应用程序依赖于Spring State Machine(为简化起见,还有Lombok)。 从Spring Starter页面或从Intellij IDEA之类的IDE(也使用Spring starter模板)生成一个非常容易。

要实际使用状态机,应在应用程序类中启用它:

@SpringBootApplication
@EnableStateMachine
public class Application implements CommandLineRunner {private final StateMachine<BookStates, BookEvents> stateMachine;@Autowiredpublic Application(StateMachine<BookStates, BookEvents> stateMachine) {this.stateMachine = stateMachine;}public static void main(String[] args) {SpringApplication.run(Application.class, args);}@Overridepublic void run(String... args) {stateMachine.start();stateMachine.sendEvent(BookEvents.RETURN);stateMachine.sendEvent(BookEvents.BORROW);stateMachine.stop();}
}

使用@EnableStateMachine批注时,它将在应用程序启动时自动创建默认状态机。 因此可以将其注入Application类。 默认情况下,该bean将被称为stateMachine ,但是可以给它另一个名称。 我们还需要为我们的活动和州提供课程。 让我们的简单示例基于库。 我们知道图书馆的书籍可以借用或归还,也可以损坏和修理(因此无法借用)。 因此,这正是我们放入模型中的内容。

public enum BookStates {AVAILABLE,BORROWED,IN_REPAIR
}
public enum BookEvents {BORROW,RETURN,START_REPAIR,END_REPAIR
}

然后,应使用以下事务和状态来配置状态机:

@Overridepublic void configure(StateMachineStateConfigurer<BookStates, BookEvents> states) throws Exception {states.withStates().initial(BookStates.AVAILABLE).states(EnumSet.allOf(BookStates.class));}@Overridepublic void configure(StateMachineTransitionConfigurer<BookStates, BookEvents> transitions) throws Exception {transitions.withExternal().source(BookStates.AVAILABLE).target(BookStates.BORROWED).event(BookEvents.BORROW).and().withExternal().source(BookStates.BORROWED).target(BookStates.AVAILABLE).event(BookEvents.RETURN).and().withExternal().source(BookStates.AVAILABLE).target(BookStates.IN_REPAIR).event(BookEvents.START_REPAIR).and().withExternal().source(BookStates.IN_REPAIR).target(BookStates.AVAILABLE).event(BookEvents.END_REPAIR);
}

最后但并非最不重要的一点是,我们允许状态机自动启动(默认情况下不会启动)。

@Overridepublic void configure(StateMachineConfigurationConfigurer<BookStates, BookEvents> config) throws Exception {config.withConfiguration().autoStartup(true);
}

现在我们可以在应用程序中使用它,看看会发生什么!

@Overridepublic void run(String... args) {boolean returnAccepted = stateMachine.sendEvent(BookEvents.RETURN);logger.info("return accepted: " + returnAccepted);boolean borrowAccepted = stateMachine.sendEvent(BookEvents.BORROW);logger.info("borrow accepted: " + borrowAccepted);
}

运行应用程序时,我们在日志中看到以下内容:

2018-07-07 13:46:05.096 INFO 37417 --- [ main] STATE MACHINE : return accepted: false
2018-07-07 13:46:05.098 INFO 37417 --- [ main] STATE MACHINE : borrow accepted: true

我故意先打电话给RETURN,看看它会失败。 但是,它无一例外都失败:该操作未被接受,并且计算机保持在AVAILABLE状态,这使得再次执行BORROW成为可能。 那么,如果我们交换两个呼叫会怎样?

2018-07-07 13:49:46.218 INFO 37496 --- [ main] STATE MACHINE : borrow accepted: true
2018-07-07 13:49:46.218 INFO 37496 --- [ main] STATE MACHINE : return accepted: true

这意味着可以接受正确的交互。 但是,如果我们想更清楚地了解发生了什么,该怎么办? 一种方法是为状态更改配置处理程序:

@Overridepublic void configure(StateMachineStateConfigurer<BookStates, BookEvents> states) throws Exception {states.withStates().initial(BookStates.AVAILABLE).state(BookStates.AVAILABLE, entryAction(), exitAction()).state(BookStates.BORROWED, entryAction(), exitAction()).state(BookStates.IN_REPAIR, entryAction(), exitAction());}@Beanpublic Action<BookStates, BookEvents> entryAction() {return ctx -> LOGGER.info("Entry action {} to get from {} to {}",ctx.getEvent(),getStateInfo(ctx.getSource()),getStateInfo(ctx.getTarget()));}@Beanpublic Action<BookStates, BookEvents> exitAction() {return ctx -> LOGGER.info("Exit action {} to get from {} to {}",ctx.getEvent(),getStateInfo(ctx.getSource()),getStateInfo(ctx.getTarget()));
}
2018-07-07 13:53:59.940 INFO 37579 --- [ main] STATE MACHINE : Entry action null to get from EMPTY STATE to AVAILABLE
2018-07-07 13:54:00.051 INFO 37579 --- [ main] STATE MACHINE : return accepted: false
2018-07-07 13:54:00.052 INFO 37579 --- [ main] STATE MACHINE : Exit action BORROW to get from AVAILABLE to BORROWED
2018-07-07 13:54:00.052 INFO 37579 --- [ main] STATE MACHINE : Entry action BORROW to get from AVAILABLE to BORROWED
2018-07-07 13:54:00.053 INFO 37579 --- [ main] STATE MACHINE : borrow accepted: true
2018-07-07 13:54:00.053 INFO 37579 --- [ main] STATE MACHINE : Exit action RETURN to get from BORROWED to AVAILABLE
2018-07-07 13:54:00.053 INFO 37579 --- [ main] STATE MACHINE : Entry action RETURN to get from BORROWED to AVAILABLE
2018-07-07 13:54:00.053 INFO 37579 --- [ main] STATE MACHINE : return accepted: true

另一种方法是定义一个成熟的侦听器:

public class LoggingMashineListener implements StateMachineListener<BookStates, BookEvents> {private static final Logger LOGGER = LoggingUtils.LOGGER;@Overridepublic void stateChanged(State<BookStates, BookEvents> from, State<BookStates, BookEvents> to) {LOGGER.info("State changed from {} to {}", getStateInfo(from), getStateInfo(to));}@Overridepublic void stateEntered(State<BookStates, BookEvents> state) {LOGGER.info("Entered state {}", getStateInfo(state));}@Overridepublic void stateExited(State<BookStates, BookEvents> state) {LOGGER.info("Exited state {}", getStateInfo(state));}@Overridepublic void eventNotAccepted(Message event) {LOGGER.error("Event not accepted: {}", event.getPayload());}@Overridepublic void transition(Transition<BookStates, BookEvents> transition) {// Too much logging spoils the code =)}@Overridepublic void transitionStarted(Transition<BookStates, BookEvents> transition) {// Too much logging spoils the code =)}@Overridepublic void transitionEnded(Transition<BookStates, BookEvents> transition) {// Too much logging spoils the code =)}@Overridepublic void stateMachineStarted(StateMachine<BookStates, BookEvents> stateMachine) {LOGGER.info("Machine started: {}", stateMachine);}@Overridepublic void stateMachineStopped(StateMachine<BookStates, BookEvents> stateMachine) {LOGGER.info("Machine stopped: {}", stateMachine);}@Overridepublic void stateMachineError(StateMachine<BookStates, BookEvents> stateMachine, Exception exception) {LOGGER.error("Machine error: {}", stateMachine);}@Overridepublic void extendedStateChanged(Object key, Object value) {LOGGER.info("Extended state changed: [{}: {}]", key, value);}@Overridepublic void stateContext(StateContext<BookStates, BookEvents> stateContext) {// Too much logging spoils the code =)}
}

并在配置监听器后将其链接到计算机。 现在我们可以删除进入和退出侦听器,并且状态配置将返回到我们的第一个修订版(请参见上文)。

@Overridepublic void configure(StateMachineConfigurationConfigurer<BookStates, BookEvents> config) throws Exception {config.withConfiguration().autoStartup(true).listener(new LoggingMashineListener());
}

这样,您将对正在发生的事情有更多的了解:

2018-07-07 13:59:22.714 INFO 37684 --- [ main] STATE MACHINE : Entered state AVAILABLE
2018-07-07 13:59:22.716 INFO 37684 --- [ main] STATE MACHINE : State changed from EMPTY STATE to AVAILABLE
2018-07-07 13:59:22.717 INFO 37684 --- [ main] STATE MACHINE : Machine started: IN_REPAIR AVAILABLE BORROWED / AVAILABLE / uuid=815f744e-8c5c-4ab1-88d1-b5223199bc4e / id=null
2018-07-07 13:59:22.835 ERROR 37684 --- [ main] STATE MACHINE : Event not accepted: RETURN
2018-07-07 13:59:22.836 INFO 37684 --- [ main] STATE MACHINE : return accepted: false
2018-07-07 13:59:22.837 INFO 37684 --- [ main] STATE MACHINE : Exited state AVAILABLE
2018-07-07 13:59:22.838 INFO 37684 --- [ main] STATE MACHINE : Entered state BORROWED
2018-07-07 13:59:22.838 INFO 37684 --- [ main] STATE MACHINE : State changed from AVAILABLE to BORROWED
2018-07-07 13:59:22.839 INFO 37684 --- [ main] STATE MACHINE : borrow accepted: true
2018-07-07 13:59:22.839 INFO 37684 --- [ main] STATE MACHINE : Exited state BORROWED
2018-07-07 13:59:22.839 INFO 37684 --- [ main] STATE MACHINE : Entered state AVAILABLE
2018-07-07 13:59:22.839 INFO 37684 --- [ main] STATE MACHINE : State changed from BORROWED to AVAILABLE
2018-07-07 13:59:22.839 INFO 37684 --- [ main] STATE MACHINE : return accepted: true

什么时候需要状态机? Spring文档指出,如果满足以下条件,您已经在尝试实现状态机 :

  • 使用布尔标志或枚举对情况进行建模。
  • 具有仅对应用程序生命周期的一部分有意义的变量。
  • 遍历if / else结构并检查是否设置了特定的标志或枚举,然后进一步对当标志和枚举的某些组合存在或不存在时的处理方式作进一步的例外。

我可以想到一些示例:

  • 机器人 对于状态机来说,这通常是一个很好的例子,因为机器人通常只有几个状态,并且它们之间有不同的动作。 例如,您有一个机器人在问问题以预订酒店(一个著名的例子)。 您会问几个问题:位置,客人人数,价格范围等。每个问题都是一个州。 每个答案都是一个事件,可以转换为下一个状态。
  • 物联网 最简单的状态机具有两种状态:ON和OFF。 但是使用比电灯开关更复杂的设备,可能会在它们之间存在更多状态,并且会有更多事件进行状态转换。

Spring State Machine可以做的事情还很多。 例如, 状态可以嵌套 。 此外,还有可以配置为检查是否允许过渡的防护措施 ,以及允许定义选择状态,接合状态等的 伪状态。 事件可以由操作或在计时器上触发 。 状态机可以持久化以提高性能。 要浏览所有内容,您需要研究Spring State Machine文档并确定适合您的特定情况的文档。 在这里,我们仅轻轻地刮擦了表面。

您可以观看有关Spring State Machine的视频 ,或研究完整的规范以了解有关该主题的更多信息。

可以在这里找到本文的项目源。

翻译自: https://www.javacodegeeks.com/2018/07/spring-state-machine.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/345615.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【渝粤题库】国家开放大学2021春2097民法学(1)题目

试卷代号&#xff1a;2097 2021年春季学期期末统一考试 民法学(1) 试题 2021年7月 一、单项选择题&#xff08;每小题有四个备选答案&#xff0c;有一个正确的&#xff0c;请将正确答案的序号填在题干的括号内。每小题3分&#xff0c;共15分&#xff09; 1.我国法律规定&#x…

信关站、关口站、earth station、gatway

卫星通信系统上行站一般建设在电信港里&#xff08;teleport&#xff09;里&#xff0c;这种上行站规模庞大&#xff0c;一般称为earth station&#xff0c;他是通过SCPC, VSAT或者MESH等多种卫星通讯系统为用户提供服务的核心站点&#xff0c;一般我们称为主站。远端用户使用的…

【渝粤题库】国家开放大学2021春2542行政组织学题目

试卷代号&#xff1a;2542 2021年春季学期期末统一考试 行政组织学试题 2021年7月 一、单项选择题&#xff08;每小题2分&#xff0c;共10分&#xff0c;每小题只有一项答案正确&#xff0c;请将正确答案的序号填在括号内&#xff09; 1.规范而言&#xff0c;行政组织是追求( )…

低轨卫星通信系统发展综述

最近几年低轨移动通信领域风起云涌&#xff0c;Iridium、OneWeb、Boeing、SpaceX 这些商业航天的 独角兽 都先后实施或宣布自己在这一领域雄心勃勃的计划。 通信、导航和遥感是卫星应用领域的三驾马车&#xff0c;简称 通导遥。鉴于任务特性&#xff0c;通信卫星和导航卫星通常…

【渝粤题库】国家开放大学2021春1425调剂学(本)题目

试卷代号&#xff1a;1425 2021年春季学期期末统一考试 调剂学&#xff08;本&#xff09; 试题 2021年7月 一、单项选择题&#xff08;每题2分&#xff0c;共60分&#xff09; 1.以下名词的英文缩写不正确的是&#xff08; &#xff09;。 A.世界卫生组织WHO B.中国药学会医院…

【渝粤题库】国家开放大学2021春2109刑事诉讼法学题目

试卷代号&#xff1a;2109 2021年春季学期期末统一考试 刑事诉讼法学 试题 2021年7月 一、单项选择题&#xff08;每题1分&#xff0c;共10分&#xff0c;每题只有一项答案正确&#xff0c;请将正确答案的序号填在括号内&#xff09; 1_在我国刑事诉讼中&#xff0c;犯罪嫌疑人…

【渝粤题库】国家开放大学2021春2180办公室管理题目

试卷代号&#xff1a;2180 2021年春季学期期末统一考试 办公室管理 试题 2021年7月 一、单项选择题&#xff08;请将正确答案的字母序号填在括号内&#xff0c;每小题3分&#xff0c;共15分&#xff09; 1.加强对办公用品的库存控制与监督&#xff0c;要求保证进货卡、库存卡和…

java运行时参数_运行时的Java 8参数名称

java运行时参数Java 8将引入一种更容易的方法来发现方法和构造函数的参数名称。 在Java 8之前&#xff0c;找到参数名称的方法是在编译阶段打开调试符号&#xff0c;这会在生成的类文件中添加有关参数名称的元信息&#xff0c;然后提取复杂的信息&#xff0c;需要处理字节码。…

天地一体化信息网络发展与拟态技术应用构想

天地一体化信息网络发展与拟态技术应用构想 2019-07-20 08:00 作者: 梁浩, 陈福才, 季新生, 吕平, 高彦钊 国家数字交换系统工程技术研究中心 摘要: 天地一体化信息网络是国家面向2030的重大科技工程, 现有的基础架构及由此构建的技术体系在其节点高性能处理、网络高效互联…

【渝粤题库】国家开放大学2021春2224物业管理法规题目

试卷代号&#xff1a;2224 2021年春季学期期末统一考试 物业管理法规 试题&#xff08;开卷&#xff09; 2021年7月 一、选择题&#xff08;在所给出的四个选择项中选出一个以上的正确答案&#xff0c;然后将其序号填写在题中的括号内。少选、多选、错选均不得分。每小题4分&am…

【渝粤题库】国家开放大学2021春2247社会工作政策法规题目

试卷代号&#xff1a;2247 2021年春季学期期末统一考试 社会工作政策法规 试题 2021年7月 一、单项选择题&#xff08;每题2分&#xff0c;共20分&#xff09; 1-社会工作服务购买的主体是( )。 A.国家 B.社会 C.社区 D.政府 2.夫妻双方自愿、并就离婚的相关问题的处理达成了合…

创建您的第一个servlet

在本教程中&#xff0c;我们将学习如何使用Servlet创建非常基本的Web应用程序。 Servlet是一类&#xff0c;扩展了服务器拦截和响应传入请求的功能。 Servlet是一个Web组件&#xff0c;可在服务器上进行编写&#xff0c;构建和部署&#xff0c;以创建动态Web页面。 首先&…

【渝粤题库】国家开放大学2021春2332高等数学基础题目

试卷代号&#xff1a;2332 2021年春季学期期末统一考试 高等数学基础 试题 2021年7月 导数基本公式&#xff1a; 积分基本公式&#xff1a; &#xff08;c&#xff09;′0 (xa)′axa-1 &#xff08;ax&#xff09;′axlna(a&#xff1e;0且a≠1) (ex)′ex (logax)′ (lnx)′ (…

StarLink星座最新动态及星间组网动态路由探讨

StarLink星座最新动态及星间组网动态路由探讨 2020-06-24 11:50 StarLink星座最新动态及星间组网动态路由探讨 作者 | 刘帅军、徐帆江、刘立祥、范媛媛、王大鹏 &#xff08;中国科学院软件研究所&#xff0c;天基综合信息系统重点实验室&#xff09; 一 概述 自2020年6月开…

【渝粤题库】国家开放大学2021春2411中国现代文学题目

试卷代号&#xff1a;2411 2021年春季学期期末统一考试 中国现代文学 试题&#xff08;开卷&#xff09; 2021年7月 一、单项选择题&#xff08;每题2分&#xff0c;共20分&#xff09; 要求&#xff1a;将正确答案的序号填在括号内。每题只有一个正确答案&#xff0c;错选或多…

【渝粤题库】国家开放大学2021春2503学前儿童健康教育题目

试卷代号&#xff1a;2503 2021年春季学期期末统一考试 学前儿童健康教育 试题 2021年7月 一、判断题&#xff08;每小题3分&#xff0c;共30分。要求先判断正误&#xff0c;错误的要予以改正&#xff09; 1.无机物能使骨具有韧性和弹性。( ) 2.婴儿的前囟出生时已闭合。( ) 3.…

累计分布函数CDF、互补累计分布函数CCDF、期望Expection

1 CDF 累积分布函数(Cumulative Distribution Function&#xff0c;CDF)&#xff0c;又叫分布函数&#xff0c;是概率密度函数的积分&#xff0c;能完整描述一个实随机变量X的概率分布。一般以大写CDF标记,&#xff0c;与概率密度函数probability density function&#xff08…

【渝粤题库】国家开放大学2021春2585城市轨道交通概论答案

试卷代号&#xff1a;2585 2021年春季学期期末统一考试 城市轨道交通概论 试题答案及评分标准 &#xff08;供参考&#xff09; 2021年7月 一、单项选择题&#xff08;每小题2分&#xff0c;共20分&#xff0c;将正确答案选项的字母填入题目的括号内&#xff09; 1.C 2.D 3.B 4…

【渝粤题库】国家开放大学2021春2626药事管理与法规题目

试卷代号&#xff1a;2626 2021年春季学期期末统一考试 药事管理与法规 试题&#xff08;开卷&#xff09; 2021年7月 一、最佳选择题&#xff08;从下列选项中选出一个最佳答案填入括号。30题&#xff0c;每题2分.共60分&#xff09; 1.由国家主管部门从目前应用的各类药物中经…

编程填空:学生信息处理程序_项目学生:业务层

编程填空:学生信息处理程序这是Project Student的一部分。 其他职位包括带有Jersey的Webservice Client&#xff0c;带有Jersey的 Webservice Server和带有Spring Data的Persistence 。 RESTful Webapp洋葱的第三层是业务层。 这就是应用程序的精髓所在–编写良好的持久性和We…