Рубрики
Без рубрики

Руководство по повторной попытке пружины

Краткое и практическое руководство по реализации логики повторных попыток с помощью Spring Retry

Автор оригинала: baeldung.

1. Обзор

Spring Retry обеспечивает возможность автоматического повторного вызова неудачной операции. Это полезно в тех случаях, когда ошибки могут быть временными (например, кратковременный сбой сети).

В этом уроке мы рассмотрим различные способы использования Spring Retry : аннотации, RetryTemplate и обратные вызовы.

Дальнейшее чтение:

Лучшие повторные попытки с экспоненциальным откатом и дрожанием

Руководство по устойчивости

Настройка логики повторных попыток в пакете Spring

2. Зависимости Maven

Давайте начнем с добавления зависимости spring-retry в ваш pom.xml файл :


    org.springframework.retry
    spring-retry
    1.2.5.RELEASE

Нам также необходимо добавить Spring AOP в наш проект:


    org.springframework
    spring-aspects
    5.2.8.RELEASE

Взгляните на Maven Central для последних версий зависимостей spring-retry и spring-aspects .

3. Включение Повторной Попытки Пружины

Чтобы включить повторную попытку Spring в приложении, нам нужно добавить @EnableRetry аннотацию в наш @Configuration класс:

@Configuration
@EnableRetry
public class AppConfig { ... }

4. Повторите Попытку С Помощью Пружины

4.1. @Retryable Без Восстановления

Чтобы добавить функциональность повторных попыток к методам, мы можем использовать @Retryable аннотация:

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

}

В этом примере повторная попытка предпринимается при возникновении RuntimeException .

В соответствии с поведением по умолчанию @Retryable повторная попытка может произойти до трех раз с задержкой в одну секунду между повторными попытками .

4.2. @Retryable и @Recover

Давайте теперь добавим метод восстановления с помощью @Восстановить аннотация:

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

В этом примере повторная попытка предпринимается при возникновении SQLException /. Аннотация @Recover определяет отдельный метод восстановления, когда метод @Retryable завершается с указанным исключением.

Следовательно, если повторите Попытку Обслуживания С Восстановлением метод продолжает бросать SQLException после 3 попыток восстановиться() будет вызван метод.

Обработчик восстановления должен иметь первый параметр типа Выбрасываемый (необязательно) и тот же тип возврата. Следующие аргументы заполняются из списка аргументов неудачного метода в том же порядке.

4.3. Настройка поведения @Retryable

Чтобы настроить поведение повтора, мы можем использовать параметры max Attempts и back off :

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

В приведенном выше примере будет до 2 попыток и задержка в 100 миллисекунд.

4.4. Использование свойств Пружины

Мы также можем использовать свойства в аннотации @Retryable .

Чтобы продемонстрировать это, мы увидим, как экстернализировать значения delay и maxAttempts в файл свойств .

Во-первых, давайте определим свойства в файле с именем retry Config. свойства :

retry.maxAttempts=2
retry.maxDelay=100

Затем мы проинструктируем наш класс @Configuration загрузить этот файл:

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

Наконец, мы можем ввести значения retry.max Попыток и retry.max задержки в нашем @Retryable определении:

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

Обратите внимание, что теперь мы используем выражение maxAttempts и выражение delay вместо max Attempts и delay .

5. Повторите попытку

5.1 Повторные операции

Spring Retry предоставляет RetryOperations интерфейс, который предоставляет набор методов execute() :

public interface RetryOperations {
     T execute(RetryCallback retryCallback) throws Exception;

    ...
}

RetryCallback , который является параметром execute () , является интерфейсом, который позволяет вставлять бизнес-логику, которая должна быть повторена при сбое:

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

5.2. Повторная настройка

RetryTemplate является реализацией операций повтора . Давайте настроим RetryTemplate bean в нашем @Configuration классе:

@Configuration
public 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 используется для управления отступлением между повторными попытками.

Наконец, a FixedBackOffPolicy делает паузу на фиксированный период времени, прежде чем продолжить.

5.3. Использование RetryTemplate

Для запуска кода с обработкой повторных попыток мы можем вызвать метод r retrytemplate.execute () :

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

Вместо анонимного класса мы можем использовать лямбда-выражение следующим образом:

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

6. Слушатели

Прослушиватели предоставляют дополнительные обратные вызовы при повторных попытках. Мы можем использовать их для различных сквозных задач при различных повторных попытках.

6.1. Добавление обратных Вызовов

Обратные вызовы предоставляются в интерфейсе RetryListener :

public class DefaultListenerSupport extends RetryListenerSupport {
    @Override
    public  void close(RetryContext context,
      RetryCallback callback, Throwable throwable) {
        logger.info("onClose);
        ...
        super.close(context, callback, throwable);
    }

    @Override
    public  void onError(RetryContext context,
      RetryCallback callback, Throwable throwable) {
        logger.info("onError"); 
        ...
        super.onError(context, callback, throwable);
    }

    @Override
    public  boolean open(RetryContext context,
      RetryCallback callback) {
        logger.info("onOpen);
        ...
        return super.open(context, callback);
    }
}

Обратные вызовы open и close выполняются до и после всей повторной попытки, в то время как onError применяется к отдельным вызовам RetryCallback .

6.2. Регистрация Слушателя

Затем мы регистрируем наш прослушиватель ( Поддержка прослушивателя по умолчанию) в нашем RetryTemplate bean:

@Configuration
public 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;
        });
    }
}

Как мы видим из журналов тестирования, RetryTemplate и RetryListener были правильно настроены:

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

8. Заключение

В этой статье мы рассмотрели, как использовать Spring Retry с помощью аннотаций, прослушивателей RetryTemplate, и обратных вызовов.

Исходный код примеров доступен на GitHub .