[JAVA] Implementieren Sie die deklarative Wiederholungsverarbeitung mit Spring Retry

Überblick

--Schreiben Sie ein Beispielprogramm und überprüfen Sie das Verhalten von Spring Boot + Spring Retry --Spring Retry macht das Schreiben von Code zum Ermitteln und Steuern von Verarbeitungswiederholungen überflüssig

Liste des Quellcodes des Beispielprogramms

├── build.gradle
├── settings.gradle
└── src
    └── main
        └── java
            └── info
                └── maigo
                    └── lab
                        └── sample
                            └── springretry
                                ├── Application.java
                                ├── HogeController.java
                                ├── HogeService.java
                                ├── KotsuException.java
                                ├── PonException.java
                                ├── PonKotsuRepository.java
                                └── PonKotsuRetryListener.java

Beispielprogrammübersicht

Betriebsüberprüfungsumgebung

Gradle Build-Datei

build.gradle

Fügen Sie den Abhängigkeiten zur Verwendung von Spring Retry die Implementierung'org.springframework.retry: spring-retry: 1.2.4.RELEASE 'hinzu. Fügen Sie außerdem runtime'org.springframework.boot: spring-boot-startup-aop 'hinzu, da zur Laufzeit die AOP-Klasse erforderlich ist. Informationen zum Angeben der abhängigen Bibliotheken finden Sie unter GitHub \ -spring \ -projects / spring \ -retry.


plugins {

  // The Java Plugin
  // https://docs.gradle.org/current/userguide/java_plugin.html
  id 'java'

  // Gradle - Plugin: org.springframework.boot
  // https://plugins.gradle.org/plugin/org.springframework.boot
  id 'org.springframework.boot' version '2.2.0.M4'

  // Gradle - Plugin: io.spring.dependency-management
  /// https://plugins.gradle.org/plugin/io.spring.dependency-management
  id 'io.spring.dependency-management' version '1.0.8.RELEASE'  
}

group = 'info.maigo.lab'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 11

repositories {
  mavenCentral()
  maven { url 'https://repo.spring.io/snapshot' }
  maven { url 'https://repo.spring.io/milestone' }
}

dependencies {
  implementation 'org.springframework.boot:spring-boot-starter-web:2.2.0.M4'
  implementation 'org.springframework.retry:spring-retry:1.2.4.RELEASE'
  runtime 'org.springframework.boot:spring-boot-starter-aop'
}

settings.gradle


pluginManagement {
  repositories {
    maven { url 'https://repo.spring.io/snapshot' }
    maven { url 'https://repo.spring.io/milestone' }
    gradlePluginPortal()
  }
  resolutionStrategy {
    eachPlugin {
      if (requested.id.id == 'org.springframework.boot') {
        useModule("org.springframework.boot:spring-boot-gradle-plugin:${requested.version}")
      }
    }
  }
}

rootProject.name = 'sample.springretry'

Server erstellen und starten

Generieren Sie eine JAR-Datei mit der Build-Aufgabe im Java-Plug-In von Gradle.

$ gradle build

BUILD SUCCESSFUL in 3s
3 actionable tasks: 3 executed

Führen Sie die generierte JAR-Datei mit dem Befehl Java aus. Dadurch wird der Webserver mit Spring Boot gestartet.

$ java -jar build/libs/sample.springretry-0.0.1-SNAPSHOT.jar

Quellcode

Application.java

Boot-Einstiegsklasse von Spring Boot. Die Annotation @EnableRetry ist für die Verwendung von Spring Retry angegeben.

package info.maigo.lab.sample.springretry;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.retry.annotation.EnableRetry;

@SpringBootApplication
@EnableRetry
public class Application {

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

}

HogeController.java

Controller-Klasse, die eine HTTP-Anforderung empfängt und eine Antwort zurückgibt. Wenn eine Ausnahme auftritt, wird das Ergebnis der Verarbeitung durch die Methode mit der Annotation @ExceptionHandler zurückgegeben.

package info.maigo.lab.sample.springretry;

import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HogeController {

    @Autowired
    private HogeService hogeService;

    @RequestMapping("/{message}")
    public Map<String, Object> index(@PathVariable("message") String message) {
        return hogeService.send(message);
    }

    @ExceptionHandler(Exception.class)
    public Map<String, Object> handleException(HttpServletRequest req, Exception e) {
        return new HashMap<String, Object>() {
            {
                put("handleException", e.getMessage());
            }
        };
    }
}

PonKotsuRepository.java

Eine hinterhältige Repository-Klasse. Erhöhen Sie PonException oder KotsuException mit einer bestimmten Wahrscheinlichkeit.

package info.maigo.lab.sample.springretry;

import java.util.Random;
import org.springframework.stereotype.Repository;

/**
 *Ein pompöses Repository.
 */
@Repository
public class PonKotsuRepository {

    private static final Random r = new Random(System.currentTimeMillis());

    /**
     *Hoffentlich gibt es eine Nachricht zurück, schlägt aber fast fehl.
     * @param message
     * @Rückmeldung
     * @löst PonException PonException aus
     * @löst KotsuException Tips Exception aus
     */
    public String send(String message) {
        int i = r.nextInt(5);
        if (i < 2) {
            System.out.println("PonKotsuRepository: Throws PonException.");
            throw new PonException();
        } else if (i < 4) {
            System.out.println("PonKotsuRepository: Throws KotsuException.");
            throw new KotsuException();
        } else {
            System.out.println("PonKotsuRepository: Returns a message.");
            return "1/Nachricht, die 3 nicht übermittelt: " + message;
        }
    }
}

HogeService.java

Eine Service-Klasse, die eine hinterhältige Repository-Klasse verwendet. Die Annotation @Retryable wird verwendet, um die Anzahl der Wiederholungen und die Wartezeit bis zu den Wiederholungen anzugeben. Die Methode mit der Annotation @Recover wird aufgerufen, wenn eine Ausnahme auftritt, selbst nachdem die angegebene Anzahl von Versuchen versucht wurde. Diese Methode verwendet die im letzten Versuch aufgetretene Ausnahme als erstes Argument und die Argumente der Methode mit der Annotation @Retryable nach dem zweiten Argument. Dieses Mal haben wir zwei Methoden vorbereitet, die die Annotation @Recover angeben. Eine wird verwendet, wenn eine PonException auftritt und das Ergebnis als Zeichenfolge zurückgibt. Die andere wird verwendet, wenn eine KotsuException auftritt und eine RuntimeException auslöst. Die Informationen der in Spring Retry verwendeten Anmerkung lauten Spring \ -Retry \ -Simple und ein wesentliches Code-freies Retry-Verarbeitungsframework und [org \ .springframework \ .retry \ .annotation \ (Spring Retry 1 \ .2 \ .4 \ .RELEASE API )](https://static.javadoc.io/org.springframework.retry/spring-retry/1.2. 4.RELEASE / index.html? Org / springframework / retry / annotation / package-summary.html) ist hilfreich.

package info.maigo.lab.sample.springretry;

import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;
import org.springframework.retry.annotation.Recover;

@Service
public class HogeService {

    @Autowired
    private PonKotsuRepository repository;

    @Retryable(value = {PonException.class, KotsuException.class}, maxAttempts = 3, backoff = @Backoff(delay = 1000))
    public Map<String, Object> send(String message) {
        String result = repository.send(message);
        return new HashMap<String, Object>() {
            {
                put("result", result);
            }
        };
    }

    @Recover
    public Map<String, Object> recoverSend(PonException e, String message) {
        System.out.println("recoverSend: PonException");
        return new HashMap<String, Object>() {
            {
                put("error", "Das Letzte, was passiert ist, war PonException");
            }
        };
    }

    @Recover
    public Map<String, Object> recoverSend(KotsuException e, String message) {
        System.out.println("recoverSend: KotsuException");
        throw new RuntimeException("Das Letzte, was passiert ist, war KotsuException");
    }
}

PonException.java

Pong Ausnahme. Es erbt nur RuntimeException.

package info.maigo.lab.sample.springretry;

public class PonException extends RuntimeException {
}

KotsuException.java

Tipps Ausnahme. Es erbt nur RuntimeException.

package info.maigo.lab.sample.springretry;

public class KotsuException extends RuntimeException {
}

PonKotsuRetryListener.java

Eine Klasse, die die RetryListener-Schnittstelle implementiert. Es besteht aus einem Rückruf, der während des Wiederholungsvorgangs aufgerufen wird. In dieser Implementierung wird der Status der Wiederholungsverarbeitung an die Standardausgabe ausgegeben.

package info.maigo.lab.sample.springretry;

import org.springframework.retry.RetryCallback;
import org.springframework.retry.RetryContext;
import org.springframework.retry.listener.RetryListenerSupport;
import org.springframework.stereotype.Component;

@Component
public class PonKotsuRetryListener extends RetryListenerSupport {

    @Override
    public <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
        System.out.println("PonKotsuRetryListener#close: " + getThrowableString(throwable));
        super.close(context, callback, throwable);
    }

    @Override
    public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
        System.out.println("PonKotsuRetryListener#onError: " + getThrowableString(throwable));
        super.onError(context, callback, throwable);
    }

    @Override
    public <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) {
        System.out.println("PonKotsuRetryListener#open");
        return super.open(context, callback);
    }

    private static String getThrowableString(Throwable throwable) {
        return throwable == null ? "null" : throwable.getClass().getSimpleName();
    }
}

Ausführungsbeispiel

Ausführungsbeispiel 1

JSON wird ausgegeben, wenn auf den von curl gestarteten Server zugegriffen wird.

$ curl http://localhost:8080/hello
{"result":"1/Nachricht, die 3 nicht übermittelt: hello"}

Zeigen Sie die Standardausgabe auf der Serverseite an. Die Nachricht kann normal zurückgegeben werden, indem erneut versucht wird, nachdem die Pon-Ausnahme aufgetreten ist.

PonKotsuRetryListener#open
PonKotsuRepository: Throws PonException.
PonKotsuRetryListener#onError: PonException
PonKotsuRepository: Returns a message.
PonKotsuRetryListener#close: null

Ausführungsbeispiel 2

$ curl http://localhost:8080/foo
{"error":"Das Letzte, was passiert ist, war PonException"}

Zeigen Sie die Standardausgabe auf der Serverseite an. Es tritt in der Reihenfolge Pon-Ausnahme → Kotsu-Ausnahme → Pon-Ausnahme auf. Für die letzte Pon-Ausnahme gibt PonKotsuRepository # recoverySend das Ergebnis zurück.

PonKotsuRetryListener#open
PonKotsuRepository: Throws PonException.
PonKotsuRetryListener#onError: PonException
PonKotsuRepository: Throws KotsuException.
PonKotsuRetryListener#onError: KotsuException
PonKotsuRepository: Throws PonException.
PonKotsuRetryListener#onError: PonException
recoverSend: PonException
PonKotsuRetryListener#close: PonException

Ausführungsbeispiel 3

$ curl http://localhost:8080/bar
{"handleException":"Das Letzte, was passiert ist, war KotsuException"}

Zeigen Sie die Standardausgabe auf der Serverseite an. Es tritt in der Reihenfolge Pon-Ausnahme → Kotsu-Ausnahme → Kotsu-Ausnahme auf. Für die letzte Kotsu-Ausnahme gibt HogeController # handleException das Ergebnis zurück.

PonKotsuRetryListener#open
PonKotsuRepository: Throws PonException.
PonKotsuRetryListener#onError: PonException
PonKotsuRepository: Throws KotsuException.
PonKotsuRetryListener#onError: KotsuException
PonKotsuRepository: Throws KotsuException.
PonKotsuRetryListener#onError: KotsuException
recoverSend: KotsuException
PonKotsuRetryListener#close: KotsuException

Referenzmaterial

Recommended Posts

Implementieren Sie die deklarative Wiederholungsverarbeitung mit Spring Retry
Asynchrone Verarbeitung mit Spring Boot unter Verwendung von @Async
Fehlerbehebung bei Federwiederholungen
Versuchen Sie es mit Spring JDBC
Ausführen der Erstverarbeitung mit Spring Boot Command Line Runner
Implementieren Sie GraphQL mit Spring Boot
Feder mit Kotorin --6 Asynchrone Verarbeitung
Datenverarbeitung mit Apache Flink
Implementieren Sie die Kategoriefunktion mithilfe von Vorfahren
Verwenden von Mapper mit Java (Spring)
Versuchen Sie es mit Spring Boot Security
[Swift] Asynchrone Verarbeitung mit PromiseKit
[Verarbeitung] Versuchen Sie es mit GT Force.
CSV-Ausgabeverarbeitung mit Super-CSV