
исправление spring retry 1.3.x с помощью специализированного инструментария для CVE-2026-41710
Этот проект предоставляет декларативную поддержку повторных попыток для приложений Spring. Он используется в Spring Batch, Spring Integration и других. Также поддерживаются императивные повторные попытки для явного использования.
Версия исправляет spring-retry до 2.0.13 для java8 и spring4 или spring5. Для получения дополнительной информации обратитесь к официальной версии Spring 2.0.13.
В этом разделе приводится краткое введение в начало работы со Spring Retry. Он включает декларативный пример и императивный пример.
Следующий пример показывает, как использовать Spring Retry в декларативном стиле:
@Configuration
@EnableRetry
public class Application {
@Bean
public Service service() {
return new Service();
}
}
@Service
class Service {
@Retryable(RemoteAccessException.class)
public void service() {
// ... do something
}
@Recover
public void recover(RemoteAccessException e) {
// ... panic
}
}
В этом примере вызывается метод service, и, если он завершается с ошибкой RemoteAccessException, выполняется повторная попытка
(по умолчанию до трёх раз), а затем, если она не удалась, вызывается метод recover.
В атрибутах аннотации @Retryable предусмотрены различные параметры для включения и
исключения типов исключений, ограничения числа повторных попыток и настройки политики задержки между ними.
Декларативный подход к применению обработки повторных попыток с помощью аннотации @Retryable, показанный ранее, имеет дополнительную
зависимость времени выполнения от классов AOP. Подробности о том, как разрешить эту зависимость в вашем проекте, см. в
разделе 'Java Configuration for Retry Proxies'.
В следующем примере показано, как использовать Spring Retry в императивном стиле (доступно начиная с версии 1.3):
RetryTemplate template = RetryTemplate.builder()
.maxAttempts(3)
.fixedBackoff(1000)
.retryOn(RemoteAccessException.class)
.build();
template.execute(ctx -> {
// ... do something
});
Для версий до 1.3 см. примеры в разделе RetryTemplate.
Spring Retry требует Java 1.7 и Maven 3.0.5 (или выше). Для сборки выполните следующую команду Maven:
$ mvn install
В этом разделе рассматриваются возможности Spring Retry и показано, как использовать его API.
RetryTemplateЧтобы сделать обработку более надёжной и менее подверженной сбоям, иногда полезно
автоматически повторять неудачную операцию, если она может завершиться успешно при
последующей попытке. Ошибки, которые поддаются такой обработке, носят временный характер. Например,
удалённый вызов веб-службы или службы RMI, который завершается неудачей из-за сетевого
сбоя или DeadLockLoserException при обновлении базы данных, может разрешиться сам после
непродолжительного ожидания. Для автоматизации повторных попыток таких операций в Spring Retry
предусмотрена стратегия RetryOperations. Определение интерфейса RetryOperations приведено ниже:
public interface RetryOperations {
<T> T execute(RetryCallback<T> retryCallback) throws Exception;
<T> T execute(RetryCallback<T> retryCallback, RecoveryCallback<T> recoveryCallback)
throws Exception;
<T> T execute(RetryCallback<T> retryCallback, RetryState retryState)
throws Exception, ExhaustedRetryException;
<T> T execute(RetryCallback<T> retryCallback, RecoveryCallback<T> recoveryCallback,
RetryState retryState) throws Exception;
}
Базовый callback — это простой интерфейс, который позволяет вставить некоторую бизнес-логику для повторной попытки:
public interface RetryCallback<T> {
T doWithRetry(RetryContext context) throws Throwable;
}
Обратный вызов выполняется, и если он завершается неудачей (выбрасывая Exception), он повторяется до тех пор, пока либо не завершится успешно, либо реализация не решит прервать попытки. В интерфейсе RetryOperations существует ряд перегруженных методов execute, предназначенных для различных сценариев восстановления после исчерпания всех попыток повторения, а также для работы с состоянием повторения, которое позволяет клиентам и реализациям сохранять информацию между вызовами (подробнее об этом позже).
Простейшей универсальной реализацией RetryOperations является RetryTemplate. В следующем примере показано, как его использовать:
RetryTemplate template = new RetryTemplate();
TimeoutRetryPolicy policy = new TimeoutRetryPolicy();
policy.setTimeout(30000L);
template.setRetryPolicy(policy);
Foo result = template.execute(new RetryCallback<Foo>() {
public Foo doWithRetry(RetryContext context) {
// Do stuff that might fail, e.g. webservice operation
return result;
}
});
В предыдущем примере мы выполняем вызов веб-службы и возвращаем результат пользователю. Если этот вызов завершается неудачно, он повторяется до достижения тайм-аута.
Начиная с версии 1.3 также доступна fluent-конфигурация RetryTemplate, как показано ниже:
RetryTemplate.builder()
.maxAttempts(10)
.exponentialBackoff(100, 2, 10000)
.retryOn(IOException.class)
.traversingCauses()
.build();
RetryTemplate.builder()
.fixedBackoff(10)
.withinMillis(3000)
.build();
RetryTemplate.builder()
.infiniteRetry()
.retryOn(IOException.class)
.uniformRandomBackoff(1000, 3000)
.build();
RetryContextПараметр метода для RetryCallback — это RetryContext. Многие callback-и игнорируют
контекст. Однако при необходимости его можно использовать как хранилище атрибутов для
сохранения данных на время итерации.
У RetryContext есть родительский контекст, если в том же потоке выполняется
вложенная повторная попытка. Родительский контекст иногда полезен для хранения данных,
которые должны совместно использоваться между вызовами execute.
RecoveryCallbackКогда повторные попытки исчерпаны, RetryOperations может передать управление другому
callback-у: RecoveryCallback. Чтобы использовать эту возможность, клиенты могут передать
callback-и вместе в один и тот же метод, как показано в следующем примере:
Foo foo = template.execute(new RetryCallback<Foo>() {
public Foo doWithRetry(RetryContext context) {
// business logic here
},
new RecoveryCallback<Foo>() {
Foo recover(RetryContext context) throws Exception {
// recover logic here
}
});
Если бизнес-логика не завершается успешно до того, как шаблон решает прервать выполнение, клиенту предоставляется возможность выполнить альтернативную обработку через callback восстановления.
В простейшем случае retry — это просто цикл while: RetryTemplate может продолжать попытки,
пока они не завершатся успешно или неудачно. RetryContext содержит некоторое состояние для определения
того, повторять попытку или прервать её. Однако это состояние находится в стеке, и нет необходимости
хранить его где-либо глобально. Следовательно, мы называем это «retry без сохранения состояния». Различие
между retry без сохранения состояния и с сохранением состояния заключено в реализации RetryPolicy
(RetryTemplate может обрабатывать оба варианта). При retry без сохранения состояния callback всегда выполняется
в том же потоке, в котором произошёл сбой при повторной попытке.