[JAVA] Dépannage de Spring Retry

Aperçu

Impossible de compiler

Le message d'erreur suivant est émis.

Error:(3, 44) java:Organisation du package.springframework.retry.l'annotation n'existe pas
Error:(11, 4) java:Impossible de trouver le symbole
symbole:Classe réessayable

Il semble que Spring Retry n'a pas été installé, vous pouvez donc installer Spring Retry.

Pour Apache Maven, ajoutez ce qui suit à l'élément dependencies de pom.xml.

<!-- https://mvnrepository.com/artifact/org.springframework.retry/spring-retry -->
<dependency>
  <groupId>org.springframework.retry</groupId>
  <artifactId>spring-retry</artifactId>
  <version>1.2.4.RELEASE</version>
</dependency>

Pour Gradle, ajoutez ce qui suit aux dépendances de build.gradle.

build.gradle


implementation 'org.springframework.retry:spring-retry:1.2.4.RELEASE'

Ne peut pas être exécuté (BeanCreationException se produit)

L'erreur suivante se produit.

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.aop.config.internalAutoProxyCreator': Initialization of bean failed; nested exception is java.lang.NoClassDefFoundError: org/aspectj/lang/annotation/Pointcut
Caused by: java.lang.NoClassDefFoundError: org/aspectj/lang/annotation/Pointcut
Caused by: java.lang.ClassNotFoundException: org.aspectj.lang.annotation.Pointcut

AspectJ aspectjweaver est requis lors de l'exécution de Spring Retry. Si vous utilisez Spring Boot, c'est une bonne idée d'installer Spring Boot AOP Starter.

Pour Apache Maven, ajoutez ce qui suit à l'élément dependencies de pom.xml.

<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-aop -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-aop</artifactId>
  <scope>runtime</scope>
</dependency>

Pour Gradle, ajoutez ce qui suit aux dépendances de build.gradle.

build.gradle


runtime('org.springframework.boot:spring-boot-starter-aop')

Ne sera pas retenté

Spécifiez @EnableRetry

Pour utiliser Spring Retry, il est nécessaire de spécifier l'annotation @EnableRetry dans la classe d'application, etc. comme suit.

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

@SpringBootApplication
@EnableRetry
public class DemoApplication {
  public static void main(String[] args) {
    SpringApplication.run(DemoApplication.class, args);
  }
}

Spécifiez @Service @Repository @Component etc.

Les classes non enregistrées dans le conteneur DI ne seront pas retentées. Spécifiez une annotation telle que @Service @Repository @Component dans la classe à réessayer, comme indiqué ci-dessous.

import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;

@Service
public class DemoService {

  @Retryable(
    value = {RuntimeException.class},
    maxAttempts = 3,
    backoff = @Backoff(delay = 1000))
  public String hello(String foo, String bar) {
    throw new RuntimeException("This is a sample error.");
  }

  @Recover
  public String recover(RuntimeException e, String foo, String bar) {
    throw e;
  }
}

Spécifiez @Retryable

Spécifiez le type d'exception à réessayer avec l'annotation @Retryable à la méthode avec valeur ou include (la valeur peut être utilisée comme un alias d'inclusion) comme suit. Il est également possible de spécifier le type d'exception qui n'est pas soumis à une nouvelle tentative avec exclusion.

@Retryable(
  include = {Exception.class},
  exclude = {RuntimeException.class},
  maxAttempts = 3,
  backoff = @Backoff(delay = 1000))
public String hello(String foo, String bar) {
  throw new RuntimeException("This is a sample error.");
}
@Retryable(
  value = {Exception.class},
  exclude = {RuntimeException.class},
  maxAttempts = 3,
  backoff = @Backoff(delay = 1000))
public String hello(String foo, String bar) {
  throw new RuntimeException("This is a sample error.");
}

Spécifiez @Autowired

Les classes qui ne sont pas enregistrées dans le conteneur DI ne seront pas retentées, spécifiez donc l'annotation @Autowired comme indiqué ci-dessous où vous souhaitez les utiliser.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class DemoController {

  //À l'objet de la classe où le processus de nouvelle tentative est écrit@Spécifiez Autowired
  @Autowired
  private MyRetryableService service;

  @RequestMapping("/")
  public String index() {
    return service.hello("hello", "goodbye");
  }
}

La méthode avec @Recover n'est pas appelée (ExhaustedRetryException se produit)

L'erreur suivante se produit.

org.springframework.retry.ExhaustedRetryException: Cannot locate recovery method; nested exception is java.lang.RuntimeException: This is a sample error.
    at org.springframework.retry.annotation.RecoverAnnotationRecoveryHandler.recover(RecoverAnnotationRecoveryHandler.java:61)
    at org.springframework.retry.interceptor.RetryOperationsInterceptor$ItemRecovererCallback.recover(RetryOperationsInterceptor.java:141)
    at org.springframework.retry.support.RetryTemplate.handleRetryExhausted(RetryTemplate.java:512)
    at org.springframework.retry.support.RetryTemplate.doExecute(RetryTemplate.java:351)
    at org.springframework.retry.support.RetryTemplate.execute(RetryTemplate.java:180)

La méthode avec l'annotation @Recover doit correspondre à la signature de méthode à réessayer. Plus précisément, le «type de valeur de retour» et le «type d'exception de cible de relance» sont décrits comme des arguments comme indiqué ci-dessous.

import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;

@Service
public class DemoService {

  //La valeur de retour est String
  //L'exception est RuntimeException
  @Retryable(
    value = {RuntimeException.class},
    maxAttempts = 3,
    backoff = @Backoff(delay = 1000))
  public String hello(String foo, String bar) {
    System.out.println("DemoService#hello");
    throw new RuntimeException("This is a sample error.");
  }

  //La valeur de retour est String
  //Décrivez RuntimeException, qui est une exception à réessayer, dans l'argument
  @Recover
  public String recover(RuntimeException e) {
    throw e;
  }
}

De plus, l'argument de la méthode d'origine ne doit pas nécessairement exister dans la méthode pour laquelle @Recover est spécifié, mais en l'ajoutant, la valeur transmise à la méthode d'origine est transmise en tant qu'argument, de sorte que des informations peuvent être obtenues.

import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;

@Service
public class DemoService {

  //La valeur de retour est String
  //L'exception est RuntimeException
  //Les arguments sont String foo et String bar
  @Retryable(
    value = {RuntimeException.class},
    maxAttempts = 3,
    backoff = @Backoff(delay = 1000))
  public String hello(String foo, String bar) {
    System.out.println("DemoService#hello");
    throw new RuntimeException("This is a sample error.");
  }

  //La valeur de retour est String
  //Décrivez RuntimeException, qui est une exception à réessayer, dans l'argument
  //Ajouter String foo et String bar des arguments de méthode cible de nouvelle tentative après l'argument d'exception
  @Recover
  public String recover(RuntimeException e, String foo, String bar) {
    System.out.println("foo=" + foo);
    System.out.println("bar=" + bar);
    throw e;
  }
}

Matériel de référence

Recommended Posts

Dépannage de Spring Retry
Implémenter le traitement déclaratif des tentatives à l'aide de Spring Retry
Dépannage de l'application
printemps × docker
À propos du printemps ③
Spring Java