Spring statemachine 具有两个状态机配置的持久配方
Spring statemachine Persist recipe with two state machine configurations
我正在尝试将 spring 状态机的 Persist 示例扩展到两种不同的状态机配置。
http://docs.spring.io/spring-statemachine/docs/1.0.0.RELEASE/reference/htmlsingle/#statemachine-examples-persist
所以我
- 添加了新架构
- 添加了一些测试数据
- 复制了 Persist、PersistCommand 的代码并根据我的情况调整了它们
到目前为止没什么大不了的。现在进行配置:
- 我删除了 StateMachineConfig(以及 @EnableStateMachine 注释)
- 将 StateMachineConfiguration 作为 Bean 添加到 PersistHandlerConfig 中并使用 Builder
- 复制该配置并使其适应我的用例
- 显然为我的案例创建了一个 class 订单
此外,我修改了 AbstractStateMachineCommands class 并在其中自动连接了一个状态机列表。 start/stop 和状态方法现在 start/stop 和每个状态机的打印状态(这里我不关心打印,变量)。
出现的问题是:
- 持久化不再有效
- 我可以启动应用程序和两个状态机
- 我可以使用所有 persist 和 myUseCase 调用,但无法处理持久数据。
- 如果我call persist process 1,应用将底层SM的状态更改为PROCESSING,但是peristed数据没有改变。
- 在调试中,我能够在 LifecycleObjectSupport 中解决 getTaskExecutor 方法 returns null(而在原始示例中,bean 工厂 returns 是 SyncTaskExecutor 的一个实例)。
- 此外,TestEventListener 似乎不再适用于任何状态机
- 当我在任何包含状态机 bean 的配置中使用 @EnableStateMachine 时,NPE 发生在 StateMachineConfiguration 的 afterPropertiesSet 处。
那么,谁能告诉我我哪里搞砸了?或者 Persist 配方不适用于两个状态机?
非常感谢。
代码示例:
Application.java 现在包含这些配置和实体:
@Configuration
static class PersistHandlerConfig {
@Bean
public Persist persist() throws Exception {
return new Persist(persistStateMachineHandler());
}
@Bean
public PersistStateMachineHandler persistStateMachineHandler() throws Exception {
return new PersistStateMachineHandler(persistSm());
}
@Bean
public StateMachine<String, String> persistSm() throws Exception{
Builder<String, String> builder = StateMachineBuilder.builder();
builder.configureStates()
.withStates()
.initial("PLACED")
.state("PROCESSING")
.state("SENT")
.state("DELIVERED");
builder.configureTransitions()
.withExternal()
.source("PLACED").target("PROCESSING")
.event("PROCESS")
.and()
.withExternal()
.source("PROCESSING").target("SENT")
.event("SEND")
.and()
.withExternal()
.source("SENT").target("DELIVERED")
.event("DELIVER");
return builder.build();
}
}
@Configuration
static class TicketPersistHandlerConfig {
@Bean
public TicketPersist ticketPersist() throws Exception {
return new TicketPersist(ticketPersistStateMachineHandler());
}
@Bean
public PersistStateMachineHandler ticketPersistStateMachineHandler() throws Exception {
return new PersistStateMachineHandler(buildMachine());
}
@Bean
public StateMachine<String, String> buildMachine() throws Exception {
Builder<String, String> builder = StateMachineBuilder.builder();
builder.configureStates()
.withStates()
.initial("PRINTED")
.state("BOOKED")
.state("SOLD")
.state("DELIVERED");
builder.configureTransitions()
.withExternal()
.source("PRINTED").target("BOOKED")
.event("BOOK")
.and()
.withExternal()
.source("BOOKED").target("SOLD")
.event("SELL")
.and()
.withExternal()
.source("SOLD").target("DELIVERED")
.event("DELIVER");
return builder.build();
}
}
public static class Order {
int id;
String state;
public Order(int id, String state) {
this.id = id;
this.state = state;
}
@Override
public String toString() {
return "Order [id=" + id + ", state=" + state + "]";
}
}
public static class Ticket {
int id;
String state;
public Ticket(int id, String state) {
this.id = id;
this.state = state;
}
@Override
public String toString() {
return "Ticket [id=" + id + ", state=" + state + "]";
}
}
TicketPersist.java 和 TicketPersistCommands.java 与订单相同(只是将订单替换为票证)。
我按以下方式调整了 AbstractStateMachineCommands:
@Autowired
private List<StateMachine<S, E>> stateMachines;
@CliCommand(value = "sm start", help = "Start a state machine")
public String start() {
for (StateMachine<S, E> stateMachine : stateMachines)
{
stateMachine.start();
}
return "State machines started";
}
@CliCommand(value = "sm stop", help = "Stop a state machine")
public String stop() {
for (StateMachine<S, E> stateMachine : stateMachines)
{
stateMachine.stop();
}
return "State machines stopped";
}
普通注释配置(使用 @EnableStateMachine
和适配器)和手动构建器之间存在概念上的差异。后者实际上是要在 spring 应用程序上下文之外使用,虽然您可以将从它创建的机器注册为 bean(就像您尝试做的那样),但没有应用很多自动配置。我可能需要在测试中更多地关注这个用例(其中用户 returns 来自构建器的机器注册为 @Bean
)。
如果使用 @EnableStateMachine
创建两台机器时出现 NPE,那是我需要研究的错误。您应该将 name
字段与 @EnableStateMachine
一起使用,指示如果要创建多台机器,adapter/javaconfig 将使用的 bean 名称。 @EnableStateMachine
默认为 bean 名称 stateMachine
并且具有多个具有相同名称的 @EnableStateMachine
适配器将尝试配置同一台机器。对于多台机器,它会像 @EnableStateMachine(name = "sm1")
.
TaskExecutor
的问题有点明显,但机器的 none 不应该使用您发布的代码,因为我没有看到它在任何地方创建。通常 TaskExecutor
要么来自显式设置实例,要么来自 bean 工厂(如果已设置)作为后备。在配置界面 http://docs.spring.io/spring-statemachine/docs/1.0.0.RELEASE/reference/htmlsingle/#statemachine-config-commonsettings.
中有用于设置这些的挂钩
这些示例默认使用 @EnableStateMachine
自动进行上下文集成,这意味着 spring 应用程序上下文事件发布者也已注册(手动构建器的机器不会发生这种情况) ,因此像 https://github.com/spring-projects/spring-statemachine/blob/master/spring-statemachine-samples/src/main/java/demo/CommonConfiguration.java#L57 中那样创建 ApplicationListener
的常规方法不再有效。您还可以使用 StateMachineListenerAdapter
并通过配置向机器注册。
我不会尝试围绕示例中的特定 shell 概念构建任何应用程序。 Shell 只是用来提供从命令行与机器交互的简单方法。我看起来你可以通过为所有机器使用不同的 bean 名称来避免所有麻烦,即 @EnableStateMachine(name = "sm1")
.
我将尝试根据这些用例创建一些 gh 问题。人们似乎总是以不同的方式尝试使用我们在测试中没有预料到的东西。
我尝试使用存储库模型工厂使用 2 组配置来配置状态机工厂,每组都给出一个名称。
然后当使用persist recipe时,我需要为statemachine factory传递一个statemachine id的字符串参数来获取statemachine实例并传递它来构造handler,并像示例中那样使用handler进行更新。
那么问题就来了,如何配置带参数的处理程序bean。而不是 @Autowired
处理程序或任何需要处理程序的东西,用 beanFactory.getBean()
获取它。
它仅在配方实施方面对我有用。但从技术上讲,它应该与使用模型工厂的配置一起工作。
我正在尝试将 spring 状态机的 Persist 示例扩展到两种不同的状态机配置。 http://docs.spring.io/spring-statemachine/docs/1.0.0.RELEASE/reference/htmlsingle/#statemachine-examples-persist
所以我
- 添加了新架构
- 添加了一些测试数据
- 复制了 Persist、PersistCommand 的代码并根据我的情况调整了它们
到目前为止没什么大不了的。现在进行配置:
- 我删除了 StateMachineConfig(以及 @EnableStateMachine 注释)
- 将 StateMachineConfiguration 作为 Bean 添加到 PersistHandlerConfig 中并使用 Builder
- 复制该配置并使其适应我的用例
- 显然为我的案例创建了一个 class 订单
此外,我修改了 AbstractStateMachineCommands class 并在其中自动连接了一个状态机列表。 start/stop 和状态方法现在 start/stop 和每个状态机的打印状态(这里我不关心打印,变量)。
出现的问题是:
- 持久化不再有效
- 我可以启动应用程序和两个状态机
- 我可以使用所有 persist 和 myUseCase 调用,但无法处理持久数据。
- 如果我call persist process 1,应用将底层SM的状态更改为PROCESSING,但是peristed数据没有改变。
- 在调试中,我能够在 LifecycleObjectSupport 中解决 getTaskExecutor 方法 returns null(而在原始示例中,bean 工厂 returns 是 SyncTaskExecutor 的一个实例)。
- 此外,TestEventListener 似乎不再适用于任何状态机
- 当我在任何包含状态机 bean 的配置中使用 @EnableStateMachine 时,NPE 发生在 StateMachineConfiguration 的 afterPropertiesSet 处。
那么,谁能告诉我我哪里搞砸了?或者 Persist 配方不适用于两个状态机?
非常感谢。
代码示例: Application.java 现在包含这些配置和实体:
@Configuration
static class PersistHandlerConfig {
@Bean
public Persist persist() throws Exception {
return new Persist(persistStateMachineHandler());
}
@Bean
public PersistStateMachineHandler persistStateMachineHandler() throws Exception {
return new PersistStateMachineHandler(persistSm());
}
@Bean
public StateMachine<String, String> persistSm() throws Exception{
Builder<String, String> builder = StateMachineBuilder.builder();
builder.configureStates()
.withStates()
.initial("PLACED")
.state("PROCESSING")
.state("SENT")
.state("DELIVERED");
builder.configureTransitions()
.withExternal()
.source("PLACED").target("PROCESSING")
.event("PROCESS")
.and()
.withExternal()
.source("PROCESSING").target("SENT")
.event("SEND")
.and()
.withExternal()
.source("SENT").target("DELIVERED")
.event("DELIVER");
return builder.build();
}
}
@Configuration
static class TicketPersistHandlerConfig {
@Bean
public TicketPersist ticketPersist() throws Exception {
return new TicketPersist(ticketPersistStateMachineHandler());
}
@Bean
public PersistStateMachineHandler ticketPersistStateMachineHandler() throws Exception {
return new PersistStateMachineHandler(buildMachine());
}
@Bean
public StateMachine<String, String> buildMachine() throws Exception {
Builder<String, String> builder = StateMachineBuilder.builder();
builder.configureStates()
.withStates()
.initial("PRINTED")
.state("BOOKED")
.state("SOLD")
.state("DELIVERED");
builder.configureTransitions()
.withExternal()
.source("PRINTED").target("BOOKED")
.event("BOOK")
.and()
.withExternal()
.source("BOOKED").target("SOLD")
.event("SELL")
.and()
.withExternal()
.source("SOLD").target("DELIVERED")
.event("DELIVER");
return builder.build();
}
}
public static class Order {
int id;
String state;
public Order(int id, String state) {
this.id = id;
this.state = state;
}
@Override
public String toString() {
return "Order [id=" + id + ", state=" + state + "]";
}
}
public static class Ticket {
int id;
String state;
public Ticket(int id, String state) {
this.id = id;
this.state = state;
}
@Override
public String toString() {
return "Ticket [id=" + id + ", state=" + state + "]";
}
}
TicketPersist.java 和 TicketPersistCommands.java 与订单相同(只是将订单替换为票证)。 我按以下方式调整了 AbstractStateMachineCommands:
@Autowired
private List<StateMachine<S, E>> stateMachines;
@CliCommand(value = "sm start", help = "Start a state machine")
public String start() {
for (StateMachine<S, E> stateMachine : stateMachines)
{
stateMachine.start();
}
return "State machines started";
}
@CliCommand(value = "sm stop", help = "Stop a state machine")
public String stop() {
for (StateMachine<S, E> stateMachine : stateMachines)
{
stateMachine.stop();
}
return "State machines stopped";
}
普通注释配置(使用 @EnableStateMachine
和适配器)和手动构建器之间存在概念上的差异。后者实际上是要在 spring 应用程序上下文之外使用,虽然您可以将从它创建的机器注册为 bean(就像您尝试做的那样),但没有应用很多自动配置。我可能需要在测试中更多地关注这个用例(其中用户 returns 来自构建器的机器注册为 @Bean
)。
如果使用
@EnableStateMachine
创建两台机器时出现 NPE,那是我需要研究的错误。您应该将name
字段与@EnableStateMachine
一起使用,指示如果要创建多台机器,adapter/javaconfig 将使用的 bean 名称。@EnableStateMachine
默认为 bean 名称stateMachine
并且具有多个具有相同名称的@EnableStateMachine
适配器将尝试配置同一台机器。对于多台机器,它会像@EnableStateMachine(name = "sm1")
.TaskExecutor
的问题有点明显,但机器的 none 不应该使用您发布的代码,因为我没有看到它在任何地方创建。通常TaskExecutor
要么来自显式设置实例,要么来自 bean 工厂(如果已设置)作为后备。在配置界面 http://docs.spring.io/spring-statemachine/docs/1.0.0.RELEASE/reference/htmlsingle/#statemachine-config-commonsettings. 中有用于设置这些的挂钩
这些示例默认使用
@EnableStateMachine
自动进行上下文集成,这意味着 spring 应用程序上下文事件发布者也已注册(手动构建器的机器不会发生这种情况) ,因此像 https://github.com/spring-projects/spring-statemachine/blob/master/spring-statemachine-samples/src/main/java/demo/CommonConfiguration.java#L57 中那样创建ApplicationListener
的常规方法不再有效。您还可以使用StateMachineListenerAdapter
并通过配置向机器注册。
我不会尝试围绕示例中的特定 shell 概念构建任何应用程序。 Shell 只是用来提供从命令行与机器交互的简单方法。我看起来你可以通过为所有机器使用不同的 bean 名称来避免所有麻烦,即 @EnableStateMachine(name = "sm1")
.
我将尝试根据这些用例创建一些 gh 问题。人们似乎总是以不同的方式尝试使用我们在测试中没有预料到的东西。
我尝试使用存储库模型工厂使用 2 组配置来配置状态机工厂,每组都给出一个名称。
然后当使用persist recipe时,我需要为statemachine factory传递一个statemachine id的字符串参数来获取statemachine实例并传递它来构造handler,并像示例中那样使用handler进行更新。
那么问题就来了,如何配置带参数的处理程序bean。而不是 @Autowired
处理程序或任何需要处理程序的东西,用 beanFactory.getBean()
获取它。
它仅在配方实施方面对我有用。但从技术上讲,它应该与使用模型工厂的配置一起工作。