Guia para repetição de primavera
1. Visão geral
O Spring Retry fornece a capacidade de invocar automaticamente uma operação com falha. Isso é útil quando os erros podem ser transitórios por natureza (como uma falha momentânea na rede). O Spring Retry fornece controle declarativo do processo e do comportamento baseado em políticas que é fácil de estender e personalizar.
Neste artigo, veremos como usarSpring Retry para implementar a lógica de repetição em aplicativos Spring. Também configuraremos os ouvintes para receber retornos de chamada adicionais.
2. Dependências do Maven
Vamos começar adicionando a dependência em nossopom.xml:
org.springframework.retry
spring-retry
1.1.5.RELEASE
Podemos verificar a versão mais recente despring-retry emMaven Central.
Também precisamos adicionar o Spring AOP em nosso pom.xml:
org.springframework
spring-aspects
3. Habilitando Spring Retry
Para habilitar Spring Retry em um aplicativo, precisamos adicionar a anotação@EnableRetry à nossa classe@Configuration:
@Configuration
@EnableRetry
public class AppConfig { ... }
4. Tentar novamente com anotações
Podemos fazer uma chamada de método para tentar novamente com falha usando anotações.
4.1. @Retryable
Para adicionar a funcionalidade de nova tentativa aos métodos,@Retryable pode ser usado:
@Service
public interface MyService {
@Retryable(
value = { SQLException.class },
maxAttempts = 2,
backoff = @Backoff(delay = 5000))
void retryService(String sql) throws SQLException;
...
}
Aqui, o comportamento de nova tentativa é personalizado usando os atributos de@Retryable.. Neste exemplo, a nova tentativa será tentada apenas se o método gerar umSQLException.. Haverá até 2 tentativas e um atraso de 5000 milissegundos.
Se@Retryable for usado sem nenhum atributo, se o método falhar com uma exceção, a nova tentativa será tentada até três vezes, com um atraso de um segundo.
4.2. @Recover
A anotação@Recover é usada para definir um método de recuperação separado quando um método@Retryable falha com uma exceção especificada:
@Service
public interface MyService {
...
@Recover
void recover(SQLException e, String sql);
}
Portanto, se o métodoretryService() lançar umSQLException, o métodorecover() será chamado. Um manipulador de recuperação adequado tem seu primeiro parâmetro do tipoThrowable (opcional). S Os argumentos subsequentes são preenchidos da lista de argumentos do método com falha na mesma ordem do método com falha e com o mesmo tipo de retorno.
5. RetryTemplate
5.1 RetryOperations
Spring Retry fornece a interfaceRetryOperations que fornece um conjunto de métodosexecute():
public interface RetryOperations {
T execute(RetryCallback retryCallback) throws Exception;
...
}
ORetryCallback, que é um parâmetro deexecute(), é uma interface que permite a inserção da lógica de negócios que precisa ser repetida em caso de falha:
public interface RetryCallback {
T doWithRetry(RetryContext context) throws Throwable;
}
5.2. Configuração deRetryTemplate
ORetryTemplate é uma implementação doRetryOperations. Vamos configurar um beanRetryTemplate em nossa classe@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 determina quando uma operação deve ser repetida. UmSimpleRetryPolicy é usado para tentar novamente um número fixo de vezes.
BackOffPolicy é usado para controlar o recuo entre as novas tentativas. AFixedBackOffPolicy pausa por um período fixo de tempo antes de continuar.
5.3. Usando oRetryTemplate
Para executar o código com manipulação de nova tentativa, chamamos retryTemplate.execute(): __
retryTemplate.execute(new RetryCallback() {
@Override
public Void doWithRetry(RetryContext arg0) {
myService.templateRetryService();
...
}
});
O mesmo pode ser alcançado usando uma expressão lambda em vez de uma classe anônima: __
retryTemplate.execute(arg0 -> {
myService.templateRetryService();
return null;
});
6. Configuração XML
A nova tentativa do Spring pode ser configurada por XML usando o espaço para nome do Spring AOP.
6.1. Adicionando arquivo XML
No caminho de classe, vamos adicionarretryadvice.xml:
...
...
Este exemplo usa umRetryTemplate personalizado dentro do método do interceptorxmlRetryService.
6.2. Usando configuração XML
Importeretryadvice.xml declasspathe habilite o suporte@AspectJ:
@Configuration
@EnableRetry
@EnableAspectJAutoProxy
@ImportResource("classpath:/retryadvice.xml")
public class AppConfig { ... }
7. Ouvintes
Os ouvintes fornecem retornos de chamada adicionais após novas tentativas. Eles podem ser usados para várias preocupações transversais em diferentes tentativas.
7.1. Adicionando Callbacks
Os retornos de chamada são fornecidos em uma interfaceRetryListener:
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);
}
}
Os retornos de chamadaopeneclose vêm antes e depois de toda a nova tentativa, eonError se aplica às chamadasRetryCallback individuais.
7.2. Registrando o Ouvinte
Em seguida, registramos nosso ouvinte (DefaultListenerSupport) em nosso beanRetryTemplate:
@Configuration
public class AppConfig {
...
@Bean
public RetryTemplate retryTemplate() {
RetryTemplate retryTemplate = new RetryTemplate();
...
retryTemplate.registerListener(new DefaultListenerSupport());
return retryTemplate;
}
}
8. Testando os resultados
Vamos verificar os resultados:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
classes = AppConfig.class,
loader = AnnotationConfigContextLoader.class)
public class SpringRetryTest {
@Autowired
private MyService myService;
@Autowired
private RetryTemplate retryTemplate;
@Test(expected = RuntimeException.class)
public void givenTemplateRetryService_whenCallWithException_thenRetry() {
retryTemplate.execute(arg0 -> {
myService.templateRetryService();
return null;
});
}
}
Quando executamos o caso de teste, o texto de registro abaixo significa que configuramos com sucesso oRetryTemplatee o Listener:
2017-01-09 20:04:10 [main] INFO o.b.s.DefaultListenerSupport - onOpen
2017-01-09 20:04:10 [main] INFO o.example.springretry.MyServiceImpl
- throw RuntimeException in method templateRetryService()
2017-01-09 20:04:10 [main] INFO o.b.s.DefaultListenerSupport - onError
2017-01-09 20:04:12 [main] INFO o.example.springretry.MyServiceImpl
- throw RuntimeException in method templateRetryService()
2017-01-09 20:04:12 [main] INFO o.b.s.DefaultListenerSupport - onError
2017-01-09 20:04:12 [main] INFO o.b.s.DefaultListenerSupport - onClose
9. Conclusão
Neste artigo, apresentamos o Spring Retry. Vimos exemplos de novas tentativas usando anotações eRetryTemplate. Em seguida, configuramos retornos de chamada adicionais usando ouvintes.
Você pode encontrar o código-fonte deste artigoover on GitHub.