
correção do spring retry 1.3.x com toolkit especializado para CVE-2026-41710
Este projeto fornece suporte declarativo de retry para aplicações Spring. É usado no Spring Batch, Spring Integration e outros. O retry imperativo também é suportado para uso explícito.
A versão corrige o spring-retry com 2.0.13 para java8 e spring4 ou spring5, Para mais informações, consulte a versão oficial do Spring 2.0.13
Esta seção fornece uma introdução rápida para começar com o Spring Retry. Inclui um exemplo declarativo e um exemplo imperativo.
O exemplo a seguir mostra como usar o Spring Retry em seu estilo declarativo:
@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
}
}
Este exemplo chama o método service e, se ele falhar com uma RemoteAccessException, tenta novamente
(por padrão, até três vezes) e, em seguida, tenta o método recover se não obtiver sucesso.
Há várias opções nos atributos da anotação @Retryable para incluir e
excluir tipos de exceção, limitar o número de tentativas e definir a política de backoff.
A abordagem declarativa para aplicar o tratamento de novas tentativas usando a anotação @Retryable mostrada anteriormente tem uma dependência
adicional em tempo de execução das classes AOP. Para obter detalhes sobre como resolver essa dependência em seu projeto, consulte a
seção 'Java Configuration for Retry Proxies'.
O exemplo a seguir mostra como usar o Spring Retry em seu estilo imperativo (disponível desde a versão 1.3):
RetryTemplate template = RetryTemplate.builder()
.maxAttempts(3)
.fixedBackoff(1000)
.retryOn(RemoteAccessException.class)
.build();
template.execute(ctx -> {
// ... do something
});
Para versões anteriores à 1.3, consulte os exemplos na seção RetryTemplate.
O Spring Retry requer Java 1.7 e Maven 3.0.5 (ou superior). Para compilar, execute o seguinte comando Maven:
$ mvn install
Esta seção discute os recursos do Spring Retry e mostra como usar sua API.
RetryTemplatePara tornar o processamento mais robusto e menos propenso a falhas, às vezes ajuda
repetir automaticamente uma operação que falhou, caso ela possa ter sucesso em uma tentativa subsequente.
Erros suscetíveis a esse tipo de tratamento são de natureza transitória. Por
exemplo, uma chamada remota a um serviço web ou a um serviço RMI que falha devido a uma
falha de rede ou a uma DeadLockLoserException em uma atualização de banco de dados pode se resolver após uma
breve espera. Para automatizar a repetição de tais operações, o Spring Retry possui a
estratégia RetryOperations. A definição da interface RetryOperations é a seguinte:
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;
}
O callback básico é uma interface simples que permite inserir alguma lógica de negócios a ser repetida:
public interface RetryCallback<T> {
T doWithRetry(RetryContext context) throws Throwable;
}
O callback é tentado e, se falhar (lançando uma Exception), é repetido até que tenha sucesso ou até que a implementação decida abortar. Existem vários métodos execute sobrecarregados na interface RetryOperations, para lidar com diversos casos de uso de recuperação quando todas as tentativas de repetição se esgotam e para lidar com o estado de repetição, que permite que clientes e implementações armazenem informações entre chamadas (mais sobre isso adiante).
A implementação de propósito geral mais simples de RetryOperations é RetryTemplate. O exemplo a seguir mostra como usá-la:
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;
}
});
No exemplo anterior, executamos uma chamada de serviço web e retornamos o resultado ao usuário. Se essa chamada falhar, ela é repetida até que um tempo limite seja atingido.
Desde a versão 1.3, também está disponível a configuração fluente de RetryTemplate, conforme segue:
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();
RetryContextO parâmetro de método para o RetryCallback é um RetryContext. Muitos callbacks ignoram
o contexto. No entanto, se necessário, você pode usá-lo como um saco de atributos para armazenar dados durante
a duração da iteração.
Um RetryContext tem um contexto pai se houver uma nova tentativa aninhada em andamento na mesma
thread. O contexto pai é ocasionalmente útil para armazenar dados que precisam ser compartilhados
entre chamadas para executar.
RecoveryCallbackQuando as tentativas se esgotam, o RetryOperations pode passar o controle para um callback
diferente: RecoveryCallback. Para usar esse recurso, os clientes podem passar os callbacks
juntos para o mesmo método, como mostra o exemplo a seguir:
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
}
});
Se a lógica de negócio não for bem-sucedida antes de o template decidir abortar, o cliente tem a oportunidade de realizar algum processamento alternativo por meio do callback de recuperação.
No caso mais simples, um retry é apenas um laço while: o RetryTemplate pode continuar tentando
até que tenha sucesso ou falhe. O RetryContext contém algum estado para determinar
se deve tentar novamente ou abortar. No entanto, esse estado fica na pilha, e não há necessidade de
armazená-lo globalmente em nenhum lugar. Consequentemente, chamamos isso de "retry sem estado". A distinção
entre retry sem estado e com estado está contida na implementação de RetryPolicy
(o RetryTemplate consegue lidar com ambos). Em um retry sem estado, o callback é sempre executado
na mesma thread em que falhou na nova tentativa.
Quando a falha fez com que um recurso transacional se tornasse inválido, há algumas considerações especiais. Isso não se aplica a uma simples chamada remota, porque (normalmente) não há recurso transacional, mas às vezes se aplica a uma atualização de banco de dados, especialmente ao usar Hibernate. Nesse caso, só faz sentido relançar a exceção que provocou a falha imediatamente, para que a transação possa sofrer rollback e possamos iniciar uma nova (e válida).