373 lines
9.4 KiB
Plaintext
373 lines
9.4 KiB
Plaintext
[[statemachine-getting-started]]
|
||
= Getting started
|
||
If you’re just getting started with Spring Statemachine,
|
||
this is the section for you! Here we answer the basic
|
||
“what?”, “how?” and “why?” questions. You’ll find a gentle
|
||
introduction to Spring Statemachine. We’ll then build our
|
||
first Spring Statemachine application, discussing some
|
||
core principles as we go.
|
||
|
||
== System Requirements
|
||
Spring Statemachine {revnumber} is built and tested with
|
||
JDK 8(all artifacts have JDK 7 compatibility) and Spring
|
||
Framework {spring-version} and doesn't require any other
|
||
dependencies outside of Spring Framework within its core system.
|
||
|
||
Other optional parts like <<sm-distributed>> has dependencies to
|
||
a `Zookeeper`, while <<statemachine-examples>> has dependencies
|
||
to spring-shell and spring-boot which pulls other dependencies
|
||
beyond framework itself. Also optional security and data access has
|
||
dependencies to _Spring Security_ and _Spring Data Modules_.
|
||
|
||
== Modules
|
||
The following modules are available for Spring Statemachine.
|
||
|
||
|===
|
||
|Module |Description
|
||
|
||
|spring-statemachine-core
|
||
|Core system of a Spring Statemachine.
|
||
|
||
|spring-statemachine-recipes-common
|
||
|Common recipes which doesn't require dependencies outside of a core
|
||
framework.
|
||
|
||
|spring-statemachine-kryo
|
||
|`Kryo` serializers for state machine.
|
||
|
||
|spring-statemachine-data-common
|
||
|Common support module for `Spring Data`.
|
||
|
||
|spring-statemachine-data-jpa
|
||
|Support module for `Spring Data JPA`.
|
||
|
||
|spring-statemachine-data-redis
|
||
|Support module for `Spring Data Redis`.
|
||
|
||
|spring-statemachine-data-mongodb
|
||
|Support module for `Spring Data MongoDB`.
|
||
|
||
|spring-statemachine-zookeeper
|
||
|`Zookeeper` integration for a distributed state machine.
|
||
|
||
|spring-statemachine-test
|
||
|Support module for state machine testing.
|
||
|
||
|spring-statemachine-cluster
|
||
|Support module for Spring Cloud Cluster.
|
||
|
||
|spring-statemachine-uml
|
||
|Support module for UI uml modeling with Eclipse Papyrus.
|
||
|
||
|spring-statemachine-autoconfigure
|
||
|Support module for `Spring Boot`.
|
||
|
||
|spring-statemachine-bom
|
||
|Bill of Materials pom.
|
||
|
||
|spring-statemachine-starter
|
||
|`Spring Boot` starter.
|
||
|===
|
||
|
||
== Using Gradle
|
||
Here is a typical `build.gradle` file created by https://start.spring.io:
|
||
|
||
[source,groovy,indent=0,subs="attributes+"]
|
||
----
|
||
buildscript {
|
||
ext {
|
||
springBootVersion = '{spring-boot-version}'
|
||
}
|
||
repositories {
|
||
mavenCentral()
|
||
maven { url "https://repo.spring.io/snapshot" }
|
||
maven { url "https://repo.spring.io/milestone" }
|
||
}
|
||
dependencies {
|
||
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
|
||
}
|
||
}
|
||
|
||
apply plugin: 'java'
|
||
apply plugin: 'eclipse'
|
||
apply plugin: 'org.springframework.boot'
|
||
apply plugin: 'io.spring.dependency-management'
|
||
|
||
group = 'com.example'
|
||
version = '0.0.1-SNAPSHOT'
|
||
sourceCompatibility = 1.8
|
||
|
||
repositories {
|
||
mavenCentral()
|
||
maven { url "https://repo.spring.io/snapshot" }
|
||
maven { url "https://repo.spring.io/milestone" }
|
||
}
|
||
|
||
|
||
ext {
|
||
springStatemachineVersion = '{revnumber}'
|
||
}
|
||
|
||
dependencies {
|
||
compile('org.springframework.statemachine:spring-statemachine-starter')
|
||
testCompile('org.springframework.boot:spring-boot-starter-test')
|
||
}
|
||
|
||
dependencyManagement {
|
||
imports {
|
||
mavenBom "org.springframework.statemachine:spring-statemachine-bom:${springStatemachineVersion}"
|
||
}
|
||
}
|
||
----
|
||
|
||
[NOTE]
|
||
====
|
||
Replace `0.0.1-SNAPSHOT` with a version you want to use.
|
||
====
|
||
|
||
Having a normal project structure you'd build this with command:
|
||
[source,text,indent=0]
|
||
----
|
||
# ./gradlew clean build
|
||
----
|
||
|
||
Expected Spring Boot packaged fat-jar would be `build/libs/demo-0.0.1-SNAPSHOT.jar`.
|
||
|
||
[NOTE]
|
||
====
|
||
You don't need repos `libs-milestone` and `libs-snapshot` for
|
||
production development.
|
||
====
|
||
|
||
== Using Maven
|
||
Here is a typical `pom.xml` file created by https://start.spring.io:
|
||
|
||
[source,xml,indent=0,subs="attributes+"]
|
||
----
|
||
<?xml version="1.0" encoding="UTF-8"?>
|
||
<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/xsd/maven-4.0.0.xsd">
|
||
<modelVersion>4.0.0</modelVersion>
|
||
|
||
<groupId>com.example</groupId>
|
||
<artifactId>demo</artifactId>
|
||
<version>0.0.1-SNAPSHOT</version>
|
||
<packaging>jar</packaging>
|
||
|
||
<name>gs-statemachine</name>
|
||
<description>Demo project for Spring Statemachine</description>
|
||
|
||
<parent>
|
||
<groupId>org.springframework.boot</groupId>
|
||
<artifactId>spring-boot-starter-parent</artifactId>
|
||
<version>{spring-boot-version}</version>
|
||
<relativePath/> <!-- lookup parent from repository -->
|
||
</parent>
|
||
|
||
<properties>
|
||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||
<java.version>1.8</java.version>
|
||
<spring-statemachine.version>{revnumber}</spring-statemachine.version>
|
||
</properties>
|
||
|
||
<dependencies>
|
||
<dependency>
|
||
<groupId>org.springframework.statemachine</groupId>
|
||
<artifactId>spring-statemachine-starter</artifactId>
|
||
</dependency>
|
||
|
||
<dependency>
|
||
<groupId>org.springframework.boot</groupId>
|
||
<artifactId>spring-boot-starter-test</artifactId>
|
||
<scope>test</scope>
|
||
</dependency>
|
||
</dependencies>
|
||
|
||
<dependencyManagement>
|
||
<dependencies>
|
||
<dependency>
|
||
<groupId>org.springframework.statemachine</groupId>
|
||
<artifactId>spring-statemachine-bom</artifactId>
|
||
<version>${spring-statemachine.version}</version>
|
||
<type>pom</type>
|
||
<scope>import</scope>
|
||
</dependency>
|
||
</dependencies>
|
||
</dependencyManagement>
|
||
|
||
<build>
|
||
<plugins>
|
||
<plugin>
|
||
<groupId>org.springframework.boot</groupId>
|
||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||
</plugin>
|
||
</plugins>
|
||
</build>
|
||
|
||
<repositories>
|
||
<repository>
|
||
<id>spring-snapshots</id>
|
||
<name>Spring Snapshots</name>
|
||
<url>https://repo.spring.io/snapshot</url>
|
||
<snapshots>
|
||
<enabled>true</enabled>
|
||
</snapshots>
|
||
</repository>
|
||
<repository>
|
||
<id>spring-milestones</id>
|
||
<name>Spring Milestones</name>
|
||
<url>https://repo.spring.io/milestone</url>
|
||
<snapshots>
|
||
<enabled>false</enabled>
|
||
</snapshots>
|
||
</repository>
|
||
</repositories>
|
||
|
||
<pluginRepositories>
|
||
<pluginRepository>
|
||
<id>spring-snapshots</id>
|
||
<name>Spring Snapshots</name>
|
||
<url>https://repo.spring.io/snapshot</url>
|
||
<snapshots>
|
||
<enabled>true</enabled>
|
||
</snapshots>
|
||
</pluginRepository>
|
||
<pluginRepository>
|
||
<id>spring-milestones</id>
|
||
<name>Spring Milestones</name>
|
||
<url>https://repo.spring.io/milestone</url>
|
||
<snapshots>
|
||
<enabled>false</enabled>
|
||
</snapshots>
|
||
</pluginRepository>
|
||
</pluginRepositories>
|
||
|
||
|
||
</project>
|
||
----
|
||
|
||
[NOTE]
|
||
====
|
||
Replace `0.0.1-SNAPSHOT` with a version you want to use.
|
||
====
|
||
|
||
Having a normal project structure you'd build this with command:
|
||
[source,text,indent=0]
|
||
----
|
||
# mvn clean package
|
||
----
|
||
|
||
Expected Spring Boot packaged fat-jar would be `target/demo-0.0.1-SNAPSHOT.jar`.
|
||
|
||
[NOTE]
|
||
====
|
||
You don't need repos `libs-milestone` and `libs-snapshot` for
|
||
production development.
|
||
====
|
||
|
||
== Developing your first Spring Statemachine application
|
||
Let's start by creating a simple Spring Boot `Application` class
|
||
implementing `CommandLineRunner`.
|
||
|
||
[source,java,indent=0]
|
||
----
|
||
@SpringBootApplication
|
||
public class Application implements CommandLineRunner {
|
||
|
||
public static void main(String[] args) {
|
||
SpringApplication.run(Application.class, args);
|
||
}
|
||
|
||
}
|
||
----
|
||
|
||
Add states and events:
|
||
[source,java,indent=0]
|
||
----
|
||
public enum States {
|
||
SI, S1, S2
|
||
}
|
||
|
||
public enum Events {
|
||
E1, E2
|
||
}
|
||
----
|
||
|
||
Add state machine configuration:
|
||
[source,java,indent=0]
|
||
----
|
||
@Configuration
|
||
@EnableStateMachine
|
||
public class StateMachineConfig
|
||
extends EnumStateMachineConfigurerAdapter<States, Events> {
|
||
|
||
@Override
|
||
public void configure(StateMachineConfigurationConfigurer<States, Events> config)
|
||
throws Exception {
|
||
config
|
||
.withConfiguration()
|
||
.autoStartup(true)
|
||
.listener(listener());
|
||
}
|
||
|
||
@Override
|
||
public void configure(StateMachineStateConfigurer<States, Events> states)
|
||
throws Exception {
|
||
states
|
||
.withStates()
|
||
.initial(States.SI)
|
||
.states(EnumSet.allOf(States.class));
|
||
}
|
||
|
||
@Override
|
||
public void configure(StateMachineTransitionConfigurer<States, Events> transitions)
|
||
throws Exception {
|
||
transitions
|
||
.withExternal()
|
||
.source(States.SI).target(States.S1).event(Events.E1)
|
||
.and()
|
||
.withExternal()
|
||
.source(States.S1).target(States.S2).event(Events.E2);
|
||
}
|
||
|
||
@Bean
|
||
public StateMachineListener<States, Events> listener() {
|
||
return new StateMachineListenerAdapter<States, Events>() {
|
||
@Override
|
||
public void stateChanged(State<States, Events> from, State<States, Events> to) {
|
||
System.out.println("State change to " + to.getId());
|
||
}
|
||
};
|
||
}
|
||
}
|
||
----
|
||
|
||
Implement `CommandLineRunner`, autowire `StateMachine`:
|
||
[source,java,indent=0]
|
||
----
|
||
@Autowired
|
||
private StateMachine<States, Events> stateMachine;
|
||
|
||
@Override
|
||
public void run(String... args) throws Exception {
|
||
stateMachine.sendEvent(Events.E1);
|
||
stateMachine.sendEvent(Events.E2);
|
||
}
|
||
----
|
||
|
||
Depending whether you build your application using `Gradle` or `Maven`
|
||
it's run `java -jar build/libs/gs-statemachine-0.1.0.jar` or
|
||
`java -jar target/gs-statemachine-0.1.0.jar` respectively.
|
||
|
||
What is expected for running this command is a normal Spring Boot output
|
||
but if you look closely you see lines:
|
||
|
||
[source,text,indent=0]
|
||
----
|
||
State change to SI
|
||
State change to S1
|
||
State change to S2
|
||
----
|
||
|