Java 如何从StateMachineConfiguration创建StateMachine
我有一个基于注释的状态机配置:Java 如何从StateMachineConfiguration创建StateMachine,java,spring,spring-statemachine,Java,Spring,Spring Statemachine,我有一个基于注释的状态机配置: @Component @Scope(BeanDefinition.SCOPE_PROTOTYPE) @EnableStateMachine(name = "machine1") public class Machine1 extends EnumStateMachineConfigurerAdapter<SimStates, SimEvents> { @Override public void configure(StateMach
@Component @Scope(BeanDefinition.SCOPE_PROTOTYPE)
@EnableStateMachine(name = "machine1")
public class Machine1 extends
EnumStateMachineConfigurerAdapter<SimStates, SimEvents> {
@Override
public void configure(StateMachineStateConfigurer<SimStates, SimEvents> states) throws Exception {
states.withStates()
.initial(INIT)
.state(INIT)
.state(S1)
.state(FINISH)
.end(FINISH)
;
}
...
更新:我将“无完整应用程序上下文”更新为“无隐式调用getBean(“machine1”)
”。这个问题还涉及了解spring状态机的所有工厂、适配器、配置和配置程序
我宁愿实例化Machine1并将其提供给某个构建器,
用于获取状态机实例的配置程序或适配器
支持基于注释的实例化配置(如via)或a-没有其他选项
使用绝对不会创建完整的应用程序上下文:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = { Machine1.class})
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
public class StateMachineTests {
@Autowired
private StateMachine<String, String> machine1;
@Test
public void testInitialState() throws Exception {
StatMachineTestPlan<SimState, SimEvent> plan = StateMachineTestPlanBuilder.<SimState, SimEvent>builder()
.defaultAwaitTime(2)
.stateMachine(machine1)
.step()
.expectStateChange(1)
.expectStateEntered(SimState.INITIAL)
.expectState(SimState.INITIAL)
.and()
.build()
plan.test();
}
}
有关测试的详细官方文件可用
我不希望有一个隐含的
通过
StateMachineFactory.getStateMachine(“machine1”),这将需要
应用程序上下文
通过构建器创建SM不需要任何Spring上下文
public class TestEventNotAccepted {
@Test
public void testEventNotAccepted() throws Exception {
StateMachine<String, String> machine = buildMachine();
StateMachineTestPlan<String, String> plan =
StateMachineTestPlanBuilder.<String, String>builder()
.defaultAwaitTime(2)
.stateMachine(machine)
.step()
.expectStates("SI")
.and()
.step()
.sendEvent("E2")
.and()
.build();
plan.test();
}
private StateMachine<String, String> buildMachine() throws Exception {
StateMachineBuilder.Builder<String, String> builder = StateMachineBuilder.builder();
builder.configureConfiguration()
.withConfiguration()
.taskExecutor(new SyncTaskExecutor())
.listener(customListener())
.autoStartup(true);
builder.configureStates()
.withStates()
.initial("SI")
.state("S1")
.state("S2");
builder.configureTransitions()
.withExternal()
.source("SI").target("S1")
.event("E1")
.action(c -> c.getExtendedState().getVariables().put("key1", "value1"))
.and()
.withExternal()
.source("S1").target("S2").event("E2");
return builder.build();
}
private StateMachineListener<String, String> customListener() {
return new StateMachineListenerAdapter<String, String>() {
@Override
public void eventNotAccepted(Message event) {
System.out.println("EVENT NOT ACCEPTED: " + event);
}
};
}
公共类TestEventNotAccepted{
@试验
public void testEventNotAccepted()引发异常{
StateMachine=buildMachine();
状态机测试计划=
StateMachineTestPlanBuilder.builder()
.2.预计时间(2)
.状态机
.第()步
.预期状态(“SI”)
.及()
.第()步
.sendEvent(“E2”)
.及()
.build();
计划。测试();
}
私有StateMachine buildMachine()引发异常{
StateMachineBuilder.Builder=StateMachineBuilder.Builder();
builder.configureConfiguration()
.withConfiguration()
.taskExecutor(新的SyncTaskExecutor())
.listener(customListener())
.自动启动(正确);
builder.configureStates()
.with states()
.首字母(“SI”)
.州(“S1”)
.州(“S2”);
builder.configureTransitions()
.withExternal()
.来源(“SI”).目标(“S1”)
.事件(“E1”)
.action(c->c.getExtendedState().getVariables().put(“key1”、“value1”))
.及()
.withExternal()
.来源(“S1”).目标(“S2”).事件(“E2”);
返回builder.build();
}
私有StateMachineListener customListener(){
返回新的StateMachineListenerAdapter(){
@凌驾
未接受公共无效事件(消息事件){
System.out.println(“未接受事件:+事件”);
}
};
}
我没有找到一种明确的方法将EnumStateMachineConfigureAdapter
与StateMachineBuilder.Builder
一起使用,但我使用了这种方法:
@组件
@范围(BeanDefinition.Scope\u原型)
@EnableStateMachine(name=“machine1”)
公共类Machine1扩展了EnumStateMachineConfigureAdapter{
@凌驾
public void configure(StateMachineStateConfigurer状态)引发异常{
配置状态(状态);
}
@凌驾
public void configure(StateMachineTransitionConfigurer转换)引发异常{
配置转换(转换);
}
公共静态无效配置状态(StateMachineStateConfigurer状态)引发异常{
states.with states()
.首字母(INIT)
.state(INIT)
.州(S1)
.状态(完成)
.结束(完成);
}
公共静态无效配置转换(StateMachineTransitionConfigurer状态)引发异常{
states.withTransitions()
//配置转换
;
}
}
以及在Statemachine测试中导入静态配置方法:
导入静态com.example.statemachine.Machine1.configureStates;
导入静态com.example.statemachine.Machine1.configureTransitions;
不接受公共类测试{
@试验
public void testEventNotAccepted()引发异常{
StateMachine=buildMachine();
状态机测试计划=
StateMachineTestPlanBuilder.builder()
.2.预计时间(2)
.状态机
.第()步
.ExpectState(初始)
.及()
//配置其他测试步骤
.build();
计划。测试();
}
私有StateMachine buildMachine()引发异常{
StateMachineBuilder.Builder=StateMachineBuilder.Builder();
builder.configureConfiguration()
.withConfiguration()
.taskExecutor(新的SyncTaskExecutor())
.listener(customListener())
.自动启动(正确);
配置状态(builder.configureStates());
configureTransitions(builder.configureTransitions());
返回builder.build();
}
}
因此,我能够在不构建整个Spring上下文和不使用
@SpringBootTest
的情况下对我的精确配置进行单元测试。谢谢,我知道StateMachineTestPlan
。我还知道如何使用StateMachineBuilder
创建动态状态机。但我的问题是如何从EnumSta获取动态状态机TeMachineConfigureAdapter
实例到没有应用程序上下文(因此没有默认的StateMachineFactory
)的StateMachine实例。我明白了-但是为什么需要完整的应用程序上下文来测试EnumSM实例?可以使用SpringBootTest(classes=EnumSM.class)并嘲笑其他一切(如SM守卫/SM行动/服务等)对,很好。我有fe
<dependency>
<groupId>org.springframework.statemachine</groupId>
<artifactId>spring-statemachine-test</artifactId>
<version>2.0.3.RELEASE</version> // change version to match yours
<scope>test</scope>
</dependency>
public class TestEventNotAccepted {
@Test
public void testEventNotAccepted() throws Exception {
StateMachine<String, String> machine = buildMachine();
StateMachineTestPlan<String, String> plan =
StateMachineTestPlanBuilder.<String, String>builder()
.defaultAwaitTime(2)
.stateMachine(machine)
.step()
.expectStates("SI")
.and()
.step()
.sendEvent("E2")
.and()
.build();
plan.test();
}
private StateMachine<String, String> buildMachine() throws Exception {
StateMachineBuilder.Builder<String, String> builder = StateMachineBuilder.builder();
builder.configureConfiguration()
.withConfiguration()
.taskExecutor(new SyncTaskExecutor())
.listener(customListener())
.autoStartup(true);
builder.configureStates()
.withStates()
.initial("SI")
.state("S1")
.state("S2");
builder.configureTransitions()
.withExternal()
.source("SI").target("S1")
.event("E1")
.action(c -> c.getExtendedState().getVariables().put("key1", "value1"))
.and()
.withExternal()
.source("S1").target("S2").event("E2");
return builder.build();
}
private StateMachineListener<String, String> customListener() {
return new StateMachineListenerAdapter<String, String>() {
@Override
public void eventNotAccepted(Message event) {
System.out.println("EVENT NOT ACCEPTED: " + event);
}
};
}