This time I had the opportunity to check ** spring-statement machine 1.2.12 ** depending on the purpose, so I wrote an article about what I tried at that time.
Basically, the content is a sample of the official document [7. Developing your first Spring Statemachine application](https://docs.spring.io/spring-statemachine/docs/2.0.2.RELEASE/reference/htmlsingle/#state Same as the state machine of -machine-via-builder).
However, since the sample is mainly a springboot application and config, this time the builder pattern "[13.2 State Machine via Builder]" (https://docs.spring.io/spring) that directly creates an instance of the state machine -statemachine / docs / 2.0.2.RELEASE / reference / htmlsingle / # state-machine-via-builder) ”, we will implement it as a simple console application.
Modify settings.xml to go through PROXY to get it directly from the Maven repository on the internet.
<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
<proxies>
<proxy>
<active>true</active>
<protocol>http</protocol>
<host>127.0.0.1</host>
<port>8080</port>
<username>xxxxxx</username>
<password>password</password>
<nonProxyHosts>10.*</nonProxyHosts>
</proxy>
</proxies>
</settings>
Create a blank project with quickstart of maven.
mvn archetype:generate ^
-DinteractiveMode=false ^
-DarchetypeArtifactId=maven-archetype-quickstart ^
-DgroupId=com.example.statemachie.demo ^
-DartifactId=statemachine-demo
Create a minimum pom.xml with spring-statementmachine 1.2.12 in the project created above.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example.statemachie.demo</groupId>
<artifactId>statemachine-demo</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>statemachine-demo</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<!-- spring-statemachine -->
<dependency>
<groupId>org.springframework.statemachine</groupId>
<artifactId>spring-statemachine-core</artifactId>
<version>1.2.12.RELEASE</version>
</dependency>
</dependencies>
<!-- java8 -->
<properties>
<java.version>1.8</java.version>
<maven.compiler.target>${java.version}</maven.compiler.target>
<maven.compiler.source>${java.version}</maven.compiler.source>
</properties>
</project>
I tried to get the jar file with mvn dependency: copy-dependencies -DoutputDirectory = lib
.
It's not a necessary task for implementation, but it was done to understand the dependencies.
commons-logging-1.2.jar
junit-3.8.1.jar
spring-aop-4.3.3.RELEASE.jar
spring-beans-4.3.3.RELEASE.jar
spring-context-4.3.3.RELEASE.jar
spring-core-4.3.3.RELEASE.jar
spring-expression-4.3.3.RELEASE.jar
spring-messaging-4.3.3.RELEASE.jar
spring-statemachine-core-1.2.12.RELEASE.jar
spring-tx-4.3.3.RELEASE.jar
This is the structure of the implemented file (src / main / java).
statemachine-demo\src\main\java
└─com
└─example
└─statemachie
└─demo
App.java
Events.java
SampleListener.java
States.java
The contents of the implemented file.
7.1. States.java
package com.example.statemachie.demo;
public enum States {
SI, S1, S2
}
State A simple Enum used as the state of the machine.
7.2. Events.java
package com.example.statemachie.demo;
public enum Events {
E1, E2
}
A simple Enum used as an event to change the state of a state machine.
7.3. SampleListener.java
package com.example.statemachie.demo;
import org.springframework.messaging.Message;
import org.springframework.statemachine.listener.StateMachineListenerAdapter;
import org.springframework.statemachine.state.State;
public class SampleListener extends
StateMachineListenerAdapter<States, Events> {
@Override
public void stateChanged(State<States, Events> from,
State<States, Events> to) {
System.out.println("State change to " + to.getId());
}
@Override
public void eventNotAccepted(Message<Events> event) {
System.out.println("event not accepted : " + event.getPayload());
}
}
It is a function of spring-state machine.
A listener that checks for state changes.
Define a class that inherits from StateMachineListenerAdapter
.
The stateChanged
method is called when the state is changed, and the ʻeventNotAccepted` method is called when the event is not accepted (the defined state and the event are not related, that is, an invalid event).
This time I overridden these two methods to see the state transitions.
7.4. App.java
package com.example.statemachie.demo;
import java.util.EnumSet;
import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.config.StateMachineBuilder;
import org.springframework.statemachine.config.StateMachineBuilder.Builder;
public class App {
public static void main(String[] args) {
correctStateFlow();
System.out.println("-----------------------");
incorrectStateFlow();
}
private static void correctStateFlow() {
StateMachine<States, Events> stateMachine = null;
try {
stateMachine = buildMachine();
} catch (Exception e) {
e.printStackTrace();
}
stateMachine.start();
stateMachine.sendEvent(Events.E1);
stateMachine.sendEvent(Events.E2);
System.out.println("isComplete() before call stop : "
+ stateMachine.isComplete());
stateMachine.stop();
System.out.println("isComplete() after call stop : "
+ stateMachine.isComplete());
}
private static void incorrectStateFlow() {
StateMachine<States, Events> stateMachine = null;
try {
stateMachine = buildMachine();
} catch (Exception e) {
e.printStackTrace();
}
stateMachine.start();
stateMachine.sendEvent(Events.E2);
}
private static StateMachine<States, Events> buildMachine() throws Exception {
Builder<States, Events> builder = StateMachineBuilder.builder();
builder.configureStates()
.withStates()
.initial(States.SI) // set initial state
.states(EnumSet.allOf(States.class));
builder.configureTransitions()
.withExternal() // add SI -(E1)-> S1
.source(States.SI).target(States.S1).event(Events.E1)
.and()
.withExternal() // add S1 -(E2)-> S2
.source(States.S1).target(States.S2).event(Events.E2);
SampleListener sampleLister = new SampleListener();
builder.configureConfiguration()
.withConfiguration()
.listener(sampleLister); // set listener
return builder.build();
}
}
The buildMachine ()
method creates an instance of ʻorg.springframework.statemachine.StateMachine. This process can be defined in Java config or XML file, but this time it is generated on demand with the builder pattern as explained in "Introduction". Once you have created an instance of
StateMachine, all you have to do is start the state machine with the
start () method and execute the event with the
sendEvent () `method.
correctStateFlow ()
issues events in the correct defined order, while ʻincorrectStateFlow ()` issues events in the wrong order (issues E2 events to Sugu after the initials). I tried this to see what happens in case of an illegal event transition.
It is a console log when actually moving it.
State change to SI
10 27, 2018 11:48:33 am org.springframework.statemachine.support.LifecycleObjectSupport start
information: started org.springframework.statemachine.support.DefaultStateMachineExecutor@768debd
10 27, 2018 11:48:33 am org.springframework.statemachine.support.LifecycleObjectSupport start
information: started S2 S1 SI / SI / uuid=af9655e4-645d-4dae-9f69-fd0514cd3a9a / id=null
State change to S1
State change to S2
isComplete() before call stop : false
10 27, 2018 11:48:34 am org.springframework.statemachine.support.LifecycleObjectSupport stop
information: stopped org.springframework.statemachine.support.DefaultStateMachineExecutor@768debd
10 27, 2018 11:48:34 am org.springframework.statemachine.support.LifecycleObjectSupport stop
information: stopped S2 S1 SI / / uuid=af9655e4-645d-4dae-9f69-fd0514cd3a9a / id=null
isComplete() after call stop : true
-----------------------
State change to SI
10 27, 2018 11:48:34 am org.springframework.statemachine.support.LifecycleObjectSupport start
information: started org.springframework.statemachine.support.DefaultStateMachineExecutor@387c703b
10 27, 2018 11:48:34 am org.springframework.statemachine.support.LifecycleObjectSupport start
information: started S2 S1 SI / SI / uuid=d075b6b9-8cf5-49fb-bc8e-226bb19600f2 / id=null
event not accepted : E2
The standard output output by the event listener and the debug log when the start ()
and stop ()
methods are called are output.
When you start a state machine with start ()
, it first changes to the state of SI
, which is the initial state defined in initial.
Executing event ʻE1 while the state is
SIchanges the state to
S1. If event ʻE2
is executed while the state is S1
, the state will be changed to S2
.
Even if the state is S2
, ʻisComplete ()returns
falsebecause the state machine is up. Exiting the state machine with
stop () terminates the state machine, so ʻisComplete ()
returns true
.
Due to the relationship between state and event, the state is not changed even if you try to make an undefined transition state.
In the sample, the event ʻE2 was executed with the state of
SI` in the initial state.
The result is output by the event listener, but the event was not accepted.
This time I tried a sample of the official document of Spring State machine with a builder pattern. I hope you have somehow understood the outline of Spring State machine.
However, it seems that further verification is required to use the Spring State machine in an actual system.
Since the state is managed by the instance of StateMachine
in the first place, it is unclear how to manage the state transition of long term (approval flow with user approval etc.).
Documents are persisted by REDIS (28.3 Using Redis) And examples of state management in Web systems (47. Event Service) Is listed, but this is only supported by changing the scope of the bean.
However, the feeling of using it was very easy, so I thought it would be useful if I could find a way to apply the Spring State machine.
Recommended Posts