[JAVA] J'ai essayé la machine Spring State

1.Tout d'abord

Cette fois, j'ai eu l'occasion de vérifier ** spring-statement machine 1.2.12 ** en fonction de mes besoins, j'ai donc écrit un article sur ce que j'avais essayé à ce moment-là.

Fondamentalement, le contenu est un échantillon du document officiel [7. Développement de votre première application Spring Statemachine](https://docs.spring.io/spring-statemachine/docs/2.0.2.RELEASE/reference/htmlsingle/#state -machine-via-builder) est identique à la machine à états.

Cependant, comme l'exemple est principalement une application et une configuration Springboot, cette fois le modèle de générateur "[13.2 State Machine via Builder]" (https://docs.spring.io/spring) qui crée directement une instance de la machine d'état -statemachine / docs / 2.0.2.RELEASE / reference / htmlsingle / # state-machine-via-builder) », nous allons l'implémenter comme une simple application console.

2. Modifiez .m2 / settings.xml (si nécessaire)

Modifiez settings.xml pour passer par PROXY pour l'obtenir directement à partir du référentiel Maven sur 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>

3. Créez un projet vierge avec maven

Créez un projet vierge avec le démarrage rapide de maven.

mvn archetype:generate ^
-DinteractiveMode=false ^
-DarchetypeArtifactId=maven-archetype-quickstart ^
-DgroupId=com.example.statemachie.demo ^
-DartifactId=statemachine-demo

4. Modifiez pom.xml

Créez un pom.xml minimal avec spring-statementmachine 1.2.12 dans le projet créé ci-dessus.

<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>

5. Liste des bibliothèques dépendantes

J'ai essayé d'obtenir le fichier jar avec mvn dependency: copy-dependencies -DoutputDirectory = lib. Ce n'est pas une tâche nécessaire pour l'implémentation, mais cela a été fait pour comprendre les dépendances.

    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

6. Structure des fichiers (src / main / java)

C'est la structure du fichier implémenté (src / main / java).

statemachine-demo\src\main\java
└─com
    └─example
        └─statemachie
            └─demo
                    App.java
                    Events.java
                    SampleListener.java
                    States.java

7. Mise en œuvre

Le contenu du fichier implémenté.

7.1. States.java

package com.example.statemachie.demo;

public enum States {
    SI, S1, S2
}

State Une simple Enum utilisée comme état de la machine.

7.2. Events.java

package com.example.statemachie.demo;

public enum Events {
    E1, E2
}

State Une simple Enum utilisée comme événement pour changer l'état d'une 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());
    }
}

C'est une fonction de la machine à ressort. Un écouteur qui vérifie les changements d'état. Définissez une classe qui hérite de StateMachineListenerAdapter. La méthode stateChanged est appelée lorsque l'état change, et la méthode ʻeventNotAccepted` est appelée lorsque l'événement n'est pas accepté (l'état défini et l'événement ne sont pas liés, c'est-à-dire un événement invalide). Cette fois, j'ai remplacé ces deux méthodes pour voir les transitions d'état.

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

La méthode buildMachine () crée une instance de ʻorg.springframework.statemachine.StateMachine. Ce processus peut être défini dans la configuration Java ou dans un fichier XML, mais cette fois, il est généré à la demande avec le modèle de générateur comme expliqué dans "Introduction". Une fois que vous avez créé une instance de StateMachine, tout ce que vous avez à faire est de démarrer la machine à états avec la méthode start () et d'exécuter l'événement avec la méthode sendEvent () `.

correctStateFlow () émet les événements dans le bon ordre que vous définissez, tandis que ʻincorrectStateFlow () `émet les événements dans le mauvais ordre (envoie les événements E2 à Sugu après les initiales). J'ai essayé ceci pour voir ce qui se passe en cas de transition d'événement illégale.

8. Résultat de l'exécution

C'est un journal de console lorsque je l'ai déplacé.

State change to SI
10 27, 2018 11:48:33 h org.springframework.statemachine.support.LifecycleObjectSupport start
information: started org.springframework.statemachine.support.DefaultStateMachineExecutor@768debd
10 27, 2018 11:48:33 h 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 h org.springframework.statemachine.support.LifecycleObjectSupport stop
information: stopped org.springframework.statemachine.support.DefaultStateMachineExecutor@768debd
10 27, 2018 11:48:34 h 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 h org.springframework.statemachine.support.LifecycleObjectSupport start
information: started org.springframework.statemachine.support.DefaultStateMachineExecutor@387c703b
10 27, 2018 11:48:34 h org.springframework.statemachine.support.LifecycleObjectSupport start
information: started S2 S1 SI  / SI / uuid=d075b6b9-8cf5-49fb-bc8e-226bb19600f2 / id=null
event not accepted : E2

La sortie standard de l'écouteur d'événements et le journal de débogage lorsque les méthodes start () et stop () sont appelées sont générées.

Lorsque vous démarrez une machine à états avec start (), elle passe d'abord à l'état de SI, qui est l'état initial défini dans initial. L'exécution de l'événement «E1» alors que l'état est «SI» change l'état en «S1». L'exécution de l'événement «E2» alors que l'état est «S1» change l'état en «S2». Même si l'état est «S2», «isComplete ()» renvoie «false» car la machine d'état est active. ʻIsComplete () renvoie true parce que quitter la machine d'état avec stop () `termine la machine d'état.

En raison de la relation entre l'état et l'événement, l'état n'est pas modifié même si vous essayez de créer un état de transition non défini. Dans l'exemple, l'événement «E2» a été exécuté avec l'état «SI» à l'état initial. Le résultat est sorti par l'écouteur d'événements, mais l'événement n'a pas été accepté.

9. Enfin

Cette fois, j'ai essayé un échantillon du document officiel de la machine Spring State avec un modèle de constructeur. J'espère que vous avez en quelque sorte compris les grandes lignes de Spring State machine. Cependant, il semble qu'une vérification supplémentaire soit nécessaire pour utiliser la machine Spring State dans un système réel. Étant donné que l'état est géré par l'instance de StateMachine en premier lieu, on ne sait pas comment gérer la transition d'état à long terme (flux d'approbation avec l'approbation de l'utilisateur, etc.). Les documents sont conservés par REDIS (28.3 Utilisation de Redis) Et des exemples de gestion d'état dans les systèmes Web (47. Event Service) Est répertorié, mais cela n'est pris en charge qu'en modifiant la portée du bean. Cependant, il était très facile à utiliser, donc j'ai pensé qu'il serait utile de trouver un moyen d'appliquer la machine Spring State.

Recommended Posts

J'ai essayé la machine Spring State
J'ai essayé Spring.
[J'ai essayé] Tutoriel de printemps
J'ai essayé Spring Batch
J'ai essayé d'utiliser Spring + Mybatis + DbUnit
J'ai essayé GraphQL avec Spring Boot
J'ai essayé Flyway avec Spring Boot
J'ai essayé le machine learning OSS d'Oracle "Tribuo"
J'ai essayé de mettre Tomcat
J'ai essayé l'initialisation paresseuse avec Spring Boot 2.2.0
J'ai essayé youtubeDataApi.
J'ai essayé de refactoriser ①
J'ai essayé Spring Data JDBC 1.0.0.BUILD-SNAPSHOT (-> 1.0.0.RELEASE)
J'ai essayé FizzBuzz.
J'ai essayé JHipster 5.1
J'ai essayé de lier JavaFX et Spring Framework.
voiture de machine d'état de Java
J'ai essayé d'exécuter Autoware
J'ai essayé d'utiliser Gson
J'ai essayé QUARKUS immédiatement
J'ai essayé d'utiliser TestNG
J'ai essayé d'utiliser Galasa
J'ai essayé node-jt400 (Programmes)
J'ai essayé node-jt400 (exécuter)
J'ai essayé node-jt400 (Transactions)
J'ai essayé d'implémenter le téléchargement de fichiers avec Spring MVC
J'ai essayé de réduire la capacité de Spring Boot
J'ai essayé de démarrer avec Spring Data JPA
[Apprentissage automatique] J'ai essayé la détection d'objets avec Create ML [détection d'objets]
J'ai essayé node-jt400 (Construction de l'environnement)
J'ai essayé DI avec Ruby
J'ai essayé node-jt400 (écriture IFS)
J'ai essayé le guide d'introduction de Spring Boot [Accès aux données avec JPA]
J'ai essayé node-jt400 (mise à jour SQL)
J'ai essayé d'utiliser azure cloud-init
J'ai essayé Drools (Java, InputStream)
J'ai essayé Rails débutant [Chapitre 1]
J'ai essayé d'utiliser Apache Wicket
J'ai essayé node-jt400 (requête SQL)
J'ai essayé d'utiliser Java REPL
J'ai essayé l'analyse du code source
J'ai essayé le problème FizzBuzz
J'ai essayé node-jt400 (flux SQL)
J'ai essayé node-jt400 (lecture IFS)
J'ai essayé Rails débutant [Chapitre 2]
J'ai essayé UPSERT avec PostgreSQL.
J'ai essayé BIND avec Docker
J'ai essayé de vérifier yum-cron
J'ai essayé de démarrer avec Swagger en utilisant Spring Boot
J'ai essayé la métaprogrammation avec Java
J'ai essayé le guide d'introduction de Spring Boot [Création d'un service Web RESTful]
J'ai essayé d'imprimer un formulaire avec Spring MVC et Jasper Reports 1/3 (paramètres Jasper Reports)
J'ai essayé de me connecter à MySQL en utilisant le modèle JDBC avec Spring MVC
J'ai essayé de créer un environnement de développement Spring MVC sur Mac
Guide de démarrage de Spring Boot [Utilisation d'un service Web RESTful]