[JAVA] Ich habe Spring State Machine ausprobiert

1. Zuallererst

Dieses Mal hatte ich die Möglichkeit, ** spring-statement machine 1.2.12 ** je nach meinen Bedürfnissen zu überprüfen, also schrieb ich einen Artikel über das, was ich damals versuchte.

Grundsätzlich handelt es sich bei dem Inhalt um ein Beispiel des offiziellen Dokuments 7. Entwickeln Ihrer ersten Spring Statemachine-Anwendung -machine-via-builder) ist dasselbe wie die Zustandsmaschine.

Da es sich bei dem Beispiel jedoch hauptsächlich um eine Springboot-Anwendung und -Konfiguration handelt, wird diesmal das Builder-Muster "[13.2 State Machine via Builder]" (https://docs.spring.io/spring) verwendet, das direkt eine Instanz der State Machine erstellt -statemachine / docs / 2.0.2.RELEASE / reference / htmlsingle / # state-machine-via-builder) “werden wir es als einfache Konsolen-App implementieren.

2. Ändern Sie .m2 / settings.xml (falls erforderlich).

Ändern Sie settings.xml, um PROXY zu durchlaufen und es direkt aus dem Maven-Repository im Internet abzurufen.

<?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. Erstellen Sie mit maven ein leeres Projekt

Erstellen Sie ein leeres Projekt mit dem Schnellstart von maven.

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

4. Ändern Sie pom.xml

Erstellen Sie mit spring-statementmachine 1.2.12 in dem oben erstellten Projekt eine minimale pom.xml.

<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 der abhängigen Bibliotheken

Ich habe versucht, die JAR-Datei mit mvn dependency: copy-dependencies -DoutputDirectory = lib abzurufen. Es ist keine notwendige Aufgabe für die Implementierung, aber es wurde getan, um die Abhängigkeiten zu verstehen.

    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. Dateistruktur (src / main / java)

Dies ist die Struktur der implementierten Datei (src / main / java).

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

7. Implementierung

Der Inhalt der implementierten Datei.

7.1. States.java

package com.example.statemachie.demo;

public enum States {
    SI, S1, S2
}

Status Eine einfache Aufzählung, die als Status der Maschine verwendet wird.

7.2. Events.java

package com.example.statemachie.demo;

public enum Events {
    E1, E2
}

Status Eine einfache Aufzählung, die als Ereignis zum Ändern des Status einer Maschine verwendet wird.

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

Es ist eine Funktion der Federzustandsmaschine. Ein Listener, der nach Statusänderungen sucht. Definieren Sie eine Klasse, die von StateMachineListenerAdapter erbt. Die Methode "stateChanged" wird aufgerufen, wenn der Status geändert wird, und die Methode "eventNotAccepted" wird aufgerufen, wenn das Ereignis nicht akzeptiert wird (der definierte Status und das Ereignis sind nicht miteinander verbunden, dh ein ungültiges Ereignis). Dieses Mal habe ich diese beiden Methoden überschrieben, um die Zustandsübergänge zu sehen.

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

Die Methode "buildMachine ()" erstellt eine Instanz von "org.springframework.statemachine.StateMachine". Dieser Prozess kann in einer Java-Konfiguration oder einer XML-Datei definiert werden, diesmal wird er jedoch bei Bedarf mit dem Builder-Muster generiert, wie in "Einführung" erläutert. Nachdem Sie eine Instanz von "StateMachine" erstellt haben, müssen Sie lediglich die Zustandsmaschine mit der Methode "start ()" starten und das Ereignis mit der Methode "sendEvent ()" ausführen.

rectStateFlow () gibt Ereignisse in der von Ihnen definierten Reihenfolge aus, währendfalseStateFlow ()Ereignisse in der falschen Reihenfolge ausgibt (gibt E2-Ereignisse nach den Initialen an Sugu aus). Ich habe dies versucht, um zu sehen, was im Falle eines illegalen Ereignisübergangs passiert.

8. Ausführungsergebnis

Es ist ein Konsolenprotokoll, als ich es tatsächlich verschoben habe.

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

Die vom Ereignis-Listener ausgegebene Standardausgabe und das Debug-Protokoll beim Aufruf der Methoden start () und stop () werden ausgegeben.

Wenn Sie eine Zustandsmaschine mit "start ()" starten, wechselt sie zuerst in den Zustand "SI", der der in initial definierte Anfangszustand ist. Wenn Sie das Ereignis "E1" ausführen, während der Status "SI" ist, wird der Status in "S1" geändert. Wenn das Ereignis "E2" ausgeführt wird, während der Zustand "S1" ist, wird der Zustand in "S2" geändert. Selbst wenn der Status "S2" ist, gibt "isComplete ()" false "zurück, da die Statusmaschine aktiv ist. isComplete () gibt true zurück, da das Beenden der Zustandsmaschine mit stop () die Zustandsmaschine beendet.

Aufgrund der Beziehung zwischen Status und Ereignis wird der Status auch dann nicht geändert, wenn Sie versuchen, einen undefinierten Übergangsstatus zu erstellen. In dem Beispiel wurde das Ereignis "E2" mit dem Zustand "SI" im Anfangszustand ausgeführt. Das Ergebnis wird vom Ereignis-Listener ausgegeben, aber das Ereignis wurde nicht akzeptiert.

9. Schließlich

Diesmal habe ich ein Beispiel des offiziellen Dokuments der Spring State-Maschine mit einem Builder-Muster ausprobiert. Ich hoffe, Sie haben die Umrisse der Spring State-Maschine irgendwie verstanden. Es scheint jedoch, dass eine weitere Überprüfung erforderlich ist, um die Spring State-Maschine in einem tatsächlichen System zu verwenden. Da der Status in erster Linie von der Instanz "StateMachine" verwaltet wird, ist unklar, wie der Statusübergang langfristig verwaltet werden soll (Genehmigungsablauf mit Benutzergenehmigung usw.). Dokumente werden von REDIS beibehalten (28.3 Verwenden von Redis). Und Beispiele für die Statusverwaltung in Websystemen (47. Event Service) Wird aufgelistet, dies wird jedoch nur durch Ändern des Bereichs der Bean unterstützt. Es war jedoch sehr einfach zu bedienen, daher hielt ich es für nützlich, wenn ich einen Weg finden könnte, die Spring State-Maschine anzuwenden.

Recommended Posts

Ich habe Spring State Machine ausprobiert
Ich habe es mit Spring versucht.
[Ich habe es versucht] Spring Tutorial
Ich habe Spring Batch ausprobiert
Ich habe versucht, Spring + Mybatis + DbUnit zu verwenden
Ich habe GraphQL mit Spring Boot ausprobiert
Ich habe Flyway mit Spring Boot ausprobiert
Ich habe das maschinelle Lernen von Oracle OSS "Tribuo" ausprobiert.
Ich habe versucht, Tomcat zu setzen
Ich habe Lazy Initialization mit Spring Boot 2.2.0 ausprobiert
Ich habe youtubeDataApi ausprobiert.
Ich habe versucht, ① umzugestalten
Ich habe Spring Data JDBC 1.0.0.BUILD-SNAPSHOT ausprobiert (-> 1.0.0.RELEASE)
Ich habe FizzBuzz ausprobiert.
Ich habe JHipster 5.1 ausprobiert
Ich habe versucht, JavaFX und Spring Framework zu verknüpfen.
Java State Machine Auto
Ich habe versucht, Autoware auszuführen
Ich habe versucht, Gson zu benutzen
Ich habe sofort QUARKUS ausprobiert
Ich habe versucht, TestNG zu verwenden
Ich habe versucht, Galasa zu benutzen
Ich habe versucht, node-jt400 (Programme)
Ich habe versucht, node-jt400 (ausführen)
Ich habe versucht, node-jt400 (Transaktionen)
Ich habe versucht, das Hochladen von Dateien mit Spring MVC zu implementieren
Ich habe versucht, die Kapazität von Spring Boot zu reduzieren
Ich habe versucht, mit Spring Data JPA zu beginnen
[Maschinelles Lernen] Ich habe die Objekterkennung mit Create ML [Objekterkennung] ausprobiert.
Ich habe versucht, node-jt400 (Umgebungskonstruktion)
Ich habe DI mit Ruby versucht
Ich habe versucht, node-jt400 (IFS schreiben)
Ich habe das Spring Boot-Einführungshandbuch [Zugriff auf Daten mit JPA] ausprobiert.
Ich habe versucht, node-jt400 (SQL Update)
Ich habe versucht, Azure Cloud-Init zu verwenden
Ich habe Drools (Java, InputStream) ausprobiert.
Ich habe Rails Anfänger ausprobiert [Kapitel 1]
Ich habe versucht, Apache Wicket zu verwenden
Ich habe versucht, node-jt400 (SQL-Abfrage)
Ich habe versucht, Java REPL zu verwenden
Ich habe versucht, den Quellcode zu analysieren
Ich habe das FizzBuzz-Problem ausprobiert
Ich habe versucht, node-jt400 (SQL-Stream)
Ich habe versucht, node-jt400 (IFS lesen)
Ich habe Rails Anfänger ausprobiert [Kapitel 2]
Ich habe UPSERT mit PostgreSQL ausprobiert.
Ich habe BIND mit Docker ausprobiert
Ich habe versucht, yum-cron zu verifizieren
Ich habe versucht, mit Swagger mit Spring Boot zu beginnen
Ich habe versucht, Metaprogrammierung mit Java
Ich habe das Spring Boot-Einführungshandbuch [Erstellen eines RESTful-Webdiensts] ausprobiert.
Ich habe versucht, ein Formular mit Spring MVC und Jasper Reports 1/3 (Jasper Reports-Einstellungen) zu drucken.
Ich habe versucht, mithilfe von JDBC Template mit Spring MVC eine Verbindung zu MySQL herzustellen
Ich habe versucht, eine Spring MVC-Entwicklungsumgebung auf einem Mac zu erstellen
Spring Boot Erste Schritte [Konsumieren eines RESTful-Webdienstes]