春季重试问题排查
总结
-
- 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