春季重试问题排查

总结

    • Spring Retry で発生する様々なトラブルについての対応策を列挙する

 

    今回の環境: Java 8 + Spring Boot 2.2.0 + Spring Retry 1.2.4

无法编译。

会输出以下类似的错误信息。

Error:(3, 44) java: パッケージorg.springframework.retry.annotationは存在しません
Error:(11, 4) java: シンボルを見つけられません
  シンボル:   クラス Retryable

可能是因为尚未引入Spring Retry,应该引入Spring Retry。

对于Apache Maven,请在pom.xml的dependencies元素中添加以下内容。

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

在Gradle中,需要在build.gradle的dependencies中添加以下内容。

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

无法执行(发生 BeanCreationException)

发生以下错误。

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

如果在运行Spring Retry时,需要使用AspectJ的aspectjweaver。
如果使用Spring Boot,则可以考虑引入Spring Boot AOP Starter。

对于 Apache Maven,需要在 pom.xml 文件的 dependencies 元素中添加以下内容。

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

在Gradle的情况下,需要在build.gradle文件的dependencies中添加以下内容。

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

不会重试

指定@EnableRetry

要使用Spring Retry,需要在应用程序类或其他类上指定@EnableRetry注解,如下所示。

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

@Service @Repository @Component 等等是用于指定的

没有注册到DI容器的类不会被视为重试目标。
对于需要执行重试操作的类,可以使用@Service、@Repository、@Component等注解来指定。

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

指定 @Retryable

可以使用 @Retryable 注释在方法中指定要重试的异常类型,可以使用 value 或 include 来指定(value 可以作为 include 的别名使用)。此外,也可以使用 exclude 来指定不需要重试的异常类型。

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

使用@Autowired进行指定

对于未在 DI 容器中注册的类,由于不能重试,因此在使用的地方需要指定以下的 @Autowired 注解。

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

@Controller
public class DemoController {

  // リトライ処理が書いてあるクラスのオブジェクトに @Autowired を指定
  @Autowired
  private MyRetryableService service;

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

调用了带有 @Recover 注解的方法未执行(导致了 ExhaustedRetryException 异常)。

出现以下的错误。

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)

需要将带有 @Recover 注解的方法与可重试方法的签名匹配。
具体来说,需要将“返回类型”和“可重试异常类型”作为参数来描述。

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 {

  // 戻り値が String
  // 例外が 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.");
  }

  // 戻り値が String
  // 引数にリトライ対象の例外である RuntimeException を記述
  @Recover
  public String recover(RuntimeException e) {
    throw e;
  }
}

还有,原来的方法的参数不需要存在于指定了@Recover注解的方法中,但通过添加该注解,可以将原方法传递的值作为参数传递,从而获取信息。

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 {

  // 戻り値が String
  // 例外が RuntimeException
  // 引数が String foo と 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.");
  }

  // 戻り値が String
  // 引数にリトライ対象の例外である RuntimeException を記述
  // 例外の引数のあとに、リトライ対象メソッド引数の String foo と String bar を追加
  @Recover
  public String recover(RuntimeException e, String foo, String bar) {
    System.out.println("foo=" + foo);
    System.out.println("bar=" + bar);
    throw e;
  }
}

仅需要一种选择:请为以下内容提供中文的本土释义:参考资料。

    • GitHub – spring-projects/spring-retry

 

    • spring-retry 1.2.4.RELEASE javadoc (org.springframework.retry)

 

    • Spring Retry の include, exclude, ExhaustedRetryException の挙動を確認する – Qiita

 

    Spring Retry を利用して宣言型のリトライ処理を実装する – Qiita
广告
将在 10 秒后关闭
bannerAds