1、概述

Spring Retry 是Spring框架中的一个组件,
它提供了主动从新调用失败操作的能力。这在谬误可能是临时产生的(如刹时网络故障)的状况下很有帮忙。

在本文中,咱们将看到应用Spring Retry的各种形式:注解、RetryTemplate以及回调。
<!--more-->

2、Maven依赖

让咱们首先将spring-retry依赖项增加到咱们的pom.xml文件中:

<dependency>    <groupId>org.springframework.retry</groupId>    <artifactId>spring-retry</artifactId>    <version>1.2.5.RELEASE</version></dependency>

咱们还须要将Spring AOP增加到咱们的我的项目中:

<dependency>    <groupId>org.springframework</groupId>    <artifactId>spring-aspects</artifactId>    <version>5.2.8.RELEASE</version></dependency>

能够查看Maven Central来获取最新版本的spring-retry
spring-aspects 依赖项。

3、开启Spring Retry

要在应用程序中启用Spring Retry,咱们须要将@EnableRetry正文增加到咱们的@Configuration类:

@Configuration@EnableRetrypublic class AppConfig { ... }

4、应用Spring Retry

4.1、@Retryable而不必复原

咱们能够应用@Retryable注解为办法增加重试性能:

@Servicepublic interface MyService {    @Retryable(value = RuntimeException.class)    void retryService(String sql);}

在这里,当抛出RuntimeException时尝试重试。

依据@Retryable的默认行为,重试最多可能产生3次,重试之间有1秒的提早。

4.2、@Retryable@Recover

当初让咱们应用@Recover注解增加一个复原办法:

@Servicepublic interface MyService {    @Retryable(value = SQLException.class)    void retryServiceWithRecovery(String sql) throws SQLException;            @Recover    void recover(SQLException e, String sql);}

这里,当抛出SQLException时重试会尝试运行。 当@Retryable办法因指定异样而失败时,@Recover注解定义了一个独自的复原办法。

因而,如果retryServiceWithRecovery办法在三次尝试之后还是抛出了SQLException,那么recover()办法将被调用。

复原处理程序的第一个参数应该是Throwable类型(可选)和雷同的返回类型。其余的参数按雷同程序从失败办法的参数列表中填充。

4.3、自定义@Retryable的行为

为了自定义重试的行为,咱们能够应用参数maxAttemptsbackoff

@Servicepublic interface MyService {    @Retryable( value = SQLException.class,       maxAttempts = 2, backoff = @Backoff(delay = 100))    void retryServiceWithCustomization(String sql) throws SQLException;}

这样最多将有两次尝试和100毫秒的提早。

4.4、应用Spring Properties

咱们还能够在@Retryable注解中应用properties。

为了演示这一点,咱们将看到如何将delaymaxAttempts的值内部化到一个properties文件中。

首先,让咱们在名为retryConfig.properties的文件中定义属性:

retry.maxAttempts=2retry.maxDelay=100

而后咱们批示@Configuration类加载这个文件:

@PropertySource("classpath:retryConfig.properties")public class AppConfig { ... }// ...

最初,咱们能够在@Retryable的定义中注入retry.maxAttemptsretry.maxDelay的值:

@Service public interface MyService {   @Retryable( value = SQLException.class, maxAttemptsExpression = "${retry.maxAttempts}",            backoff = @Backoff(delayExpression = "${retry.maxDelay}"))   void retryServiceWithExternalizedConfiguration(String sql) throws SQLException; }

请留神,咱们当初应用的是maxAttemptsExpressiondelayExpression而不是maxAttemptsdelay

5、RetryTemplate

5.1、RetryOperations

Spring Retry提供了RetryOperations接口,它提供了一组execute()办法:

public interface RetryOperations {    <T> T execute(RetryCallback<T> retryCallback) throws Exception;    ...}

execute()办法的参数RetryCallback,是一个接口,能够插入须要在失败时重试的业务逻辑:

public interface RetryCallback<T> {    T doWithRetry(RetryContext context) throws Throwable;}

5.2、RetryTemplate配置

RetryTemplateRetryOperations的一个实现。

让咱们在@Configuration类中配置一个RetryTemplate的bean:

@Configurationpublic class AppConfig {    //...    @Bean    public RetryTemplate retryTemplate() {        RetryTemplate retryTemplate = new RetryTemplate();                FixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy();        fixedBackOffPolicy.setBackOffPeriod(2000l);        retryTemplate.setBackOffPolicy(fixedBackOffPolicy);        SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();        retryPolicy.setMaxAttempts(2);        retryTemplate.setRetryPolicy(retryPolicy);                return retryTemplate;    }}

这个RetryPolicy确定了何时应该重试操作。

其中SimpleRetryPolicy定义了重试的固定次数,另一方面,BackOffPolicy用于管制重试尝试之间的回退。

最初,FixedBackOffPolicy会使重试在持续之前暂停一段固定的工夫。

5.3、应用RetryTemplate

要应用重试解决来运行代码,咱们能够调用retryTemplate.execute()办法:

retryTemplate.execute(new RetryCallback<Void, RuntimeException>() {    @Override    public Void doWithRetry(RetryContext arg0) {        myService.templateRetryService();        ...    }});

咱们能够应用lambda表达式代替匿名类:

retryTemplate.execute(arg0 -> {    myService.templateRetryService();    return null;});

6、监听器

监听器在重试时提供另外的回调。咱们能够用这些来关注跨不同重试的各个横切点。

6.1、增加回调

回调在RetryListener接口中提供:

public class DefaultListenerSupport extends RetryListenerSupport {    @Override    public <T, E extends Throwable> void close(RetryContext context,      RetryCallback<T, E> callback, Throwable throwable) {        logger.info("onClose");        ...        super.close(context, callback, throwable);    }    @Override    public <T, E extends Throwable> void onError(RetryContext context,      RetryCallback<T, E> callback, Throwable throwable) {        logger.info("onError");         ...        super.onError(context, callback, throwable);    }    @Override    public <T, E extends Throwable> boolean open(RetryContext context,      RetryCallback<T, E> callback) {        logger.info("onOpen");        ...        return super.open(context, callback);    }}

openclose的回调在整个重试之前和之后执行,而onError利用于单个RetryCallback调用。

6.2、注册监听器

接下来,咱们将咱们的监听器(DefaultListenerSupport)注册到咱们的RetryTemplate bean:

@Configurationpublic class AppConfig {    ...    @Bean    public RetryTemplate retryTemplate() {        RetryTemplate retryTemplate = new RetryTemplate();        ...        retryTemplate.registerListener(new DefaultListenerSupport());        return retryTemplate;    }}

7、测试后果

为了实现咱们的示例,让咱们验证一下后果:

@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(  classes = AppConfig.class,  loader = AnnotationConfigContextLoader.class)public class SpringRetryIntegrationTest {    @Autowired    private MyService myService;    @Autowired    private RetryTemplate retryTemplate;    @Test(expected = RuntimeException.class)    public void givenTemplateRetryService_whenCallWithException_thenRetry() {        retryTemplate.execute(arg0 -> {            myService.templateRetryService();            return null;        });    }}

从测试日志中能够看出,咱们曾经正确配置了RetryTemplateRetryListener

2020-01-09 20:04:10 [main] INFO  c.p.s.DefaultListenerSupport - onOpen 2020-01-09 20:04:10 [main] INFO  c.pinmost.springretry.MyServiceImpl - throw RuntimeException in method templateRetryService() 2020-01-09 20:04:10 [main] INFO  c.p.s.DefaultListenerSupport - onError 2020-01-09 20:04:12 [main] INFO  c.pinmost.springretry.MyServiceImpl - throw RuntimeException in method templateRetryService() 2020-01-09 20:04:12 [main] INFO  c.p.s.DefaultListenerSupport - onError 2020-01-09 20:04:12 [main] INFO  c.p.s.DefaultListenerSupport - onClose

8、论断

在本文中,咱们看到了如何应用注解、RetryTemplate和回调监听器来应用Spring Retry。

原文地址:https://www.baeldung.com/spri...

翻译:码农熊猫

更多技术干货,请拜访我的集体网站https://pinmost.com,或关注公众号【码农熊猫】