Guia para repetição de primavera

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.