Getting started

If you are just getting started with Spring Statemachine, this is the section for you! Here, we answer the basic “what?”, “how?” and “why?” questions. We start with a gentle introduction to Spring Statemachine. We then build our first Spring Statemachine application and discuss some core principles as we go.

System Requirement

Spring Statemachine 4.0.0 is built and tested with JDK 8 (all artifacts have JDK 7 compatibility) and Spring Framework 6.0.14. It does not require any other dependencies outside of Spring Framework within its core system.spring-doc.cn

Other optional parts (such as Using Distributed States) have dependencies on Zookeeper, while State Machine Examples has dependencies on spring-shell and spring-boot, which pull other dependencies beyond the framework itself. Also, the optional security and data access features have dependencies to on Spring Security and Spring Data modules.spring-doc.cn

Modules

The following table describes the modules that are available for Spring Statemachine.spring-doc.cn

Module Description

spring-statemachine-corespring-doc.cn

The core system of Spring Statemachine.spring-doc.cn

spring-statemachine-recipes-commonspring-doc.cn

Common recipes that do not require dependencies outside of the core framework.spring-doc.cn

spring-statemachine-kryospring-doc.cn

Kryo serializers for Spring Statemachine.spring-doc.cn

spring-statemachine-data-commonspring-doc.cn

Common support module for Spring Data.spring-doc.cn

spring-statemachine-data-jpaspring-doc.cn

Support module for Spring Data JPA.spring-doc.cn

spring-statemachine-data-redisspring-doc.cn

Support module for Spring Data Redis.spring-doc.cn

spring-statemachine-data-mongodbspring-doc.cn

Support module for Spring Data MongoDB.spring-doc.cn

spring-statemachine-zookeeperspring-doc.cn

Zookeeper integration for a distributed state machine.spring-doc.cn

spring-statemachine-testspring-doc.cn

Support module for state machine testing.spring-doc.cn

spring-statemachine-clusterspring-doc.cn

Support module for Spring Cloud Cluster. Note that Spring Cloud Cluster has been superseded by Spring Integration.spring-doc.cn

spring-statemachine-umlspring-doc.cn

Support module for UI UML modeling with Eclipse Papyrus.spring-doc.cn

spring-statemachine-autoconfigurespring-doc.cn

Support module for Spring Boot.spring-doc.cn

spring-statemachine-bomspring-doc.cn

Bill of Materials pom.spring-doc.cn

spring-statemachine-starterspring-doc.cn

Spring Boot starter.spring-doc.cn

Using Gradle

The following listing shows a typical build.gradle file created by choosing various settings at https://start.spring.io:spring-doc.cn

buildscript {
	ext {
		springBootVersion = '3.1.6'
	}
	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 = '4.0.0'
}

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}"
	}
}
Replace 0.0.1-SNAPSHOT with a version you want to use.

With a normal project structure, you can build this project with the following command:spring-doc.cn

# ./gradlew clean build

The expected Spring Boot-packaged fat jar would be build/libs/demo-0.0.1-SNAPSHOT.jar.spring-doc.cn

You do not need the`libs-milestone` and libs-snapshot repositories for production development.

Using Maven

The following example shows a typical pom.xml file, which was created by choosing various options at https://start.spring.io:spring-doc.cn

<?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 https://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>3.1.6</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>4.0.0</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>
Replace 0.0.1-SNAPSHOT with a version you want to use.

With a normal project structure, you can build this project with the following command:spring-doc.cn

# mvn clean package

The expected Spring Boot-packaged fat-jar would be target/demo-0.0.1-SNAPSHOT.jar.spring-doc.cn

You do not need the libs-milestone and libs-snapshot repositories for production development.

Developing Your First Spring Statemachine Application

You can start by creating a simple Spring Boot Application class that implements CommandLineRunner. The following example shows how to do so:spring-doc.cn

@SpringBootApplication
public class Application implements CommandLineRunner {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

Then you need to add states and events, as the following example shows:spring-doc.cn

public enum States {
    SI, S1, S2
}

public enum Events {
    E1, E2
}

Then you need to add state machine configuration, as the following example shows:spring-doc.cn

@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());
            }
        };
    }
}

Then you need to implement CommandLineRunner and autowire StateMachine. The following example shows how to do so:spring-doc.cn

@Autowired
private StateMachine<States, Events> stateMachine;

@Override
public void run(String... args) throws Exception {
    stateMachine.sendEvent(Events.E1);
    stateMachine.sendEvent(Events.E2);
}

Depending on whether you build your application with Gradle or Maven, you can run it by using java -jar build/libs/gs-statemachine-0.1.0.jar or java -jar target/gs-statemachine-0.1.0.jar, respectively.spring-doc.cn

The result of this command should be normal Spring Boot output. However, you should also find the following lines:spring-doc.cn

State change to SI
State change to S1
State change to S2

These lines indicate that the machine you constructed is moving from one state to another, as it should.spring-doc.cn