1, an overview of the

Spring Retry is a component in the Spring framework that provides the ability to automatically reinvoke failed operations. This is helpful in cases where the error is likely to be transient, such as a transient network failure.

In this article, we’ll look at various ways to use Spring Retry: annotations, retryTemplates, and callbacks.

2. Maven dependencies

Let’s first add the spring-retry dependency to our pom.xml file:

<dependency> <groupId>org.springframework.retry</groupId> <artifactId>spring-retry</artifactId> < version > 1.2.5. RELEASE < / version > < / dependency >

We also need to add Spring AOP to our project:

<dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> < version > 5.2.8. RELEASE < / version > < / dependency >

You can check Maven Central for the latest versions of Spring-Retry and Spring-Aspects dependencies.

3. Start Spring Retry

To enable Spring Retry in our application, we need to add the @Enableretry annotation to our @Configuration class:

public class AppConfig { ... }

4. Use Spring Retry

4.1,@RetryableWithout having to recover.

We can add retry to a method using the @Retryable annotation:

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


Here, a retry is attempted when a RuntimeException is thrown.

Depending on the default behavior of @Retryable, retries can occur up to 3 times with a delay of 1 second between retries.


Now let’s add a recovery method using the @Recover annotation:

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

Here, retry tries to run when an SQLException is thrown. The @Recover annotation defines a separate recovery method when the @Retyable method fails by specifying an exception.

Therefore, if the RetryServiceWithRecovery method throws an SQLException after three attempts, then the Recover () method will be called.

The first argument to the recovery handler should be of type Throwable (optional) and the same return type. The remaining arguments are filled in from the failed method’s argument list in the same order.

4.3. Customization@RetryableThe behavior of the

To customize the retry behavior, we can use the parameters MaxAttempts and Backoff:

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

This will result in a maximum of two attempts and a delay of 100 milliseconds.

4.4. Use Spring Properties

We can also use Properties in the @Retryable annotation.

To demonstrate this, we will see how to externalize the values for Delay and MaxAttempts into a Properties file.

First, let’s define the properties in a file called retryConfig.properties:


Then we instruct the @Configuration class to load the file:

public class AppConfig { ... }
// ...

Finally, we can inject the Retry. MaxAttempts and Retry. MaxDelay values into the definition of @Retry Attempts:

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

Note that we are now using maxAttemptsExpression and DelayExpression instead of MaxAttempts and Delay.



Spring Retry provides the RetryOperations interface, which provides a set of execute() methods:

public interface RetryOperations { <T> T execute(RetryCallback<T> retryCallback) throws Exception; . }

RetryCallback, the argument to the execute() method, is an interface to insert business logic that needs to be retried if it fails:

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


RetryTemplate is an implementation of RetryOperations.

Let’s configure a retryTemplate bean in the @Configuration class:

@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; }}

This RetryPolicy determines when the operation should be retried.

SimpleRetryPolicy defines a fixed number of retries. BackoffPolicy, on the other hand, controls fallbacks between retry attempts.

Finally, FixedBackoffPolicy suspends retries for a fixed period of time before continuing.

5.3, use,RetryTemplate

To run the code using retry processing, we can call the retryTemplate.execute() method:

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

We can use lambda expressions instead of anonymous classes:

retryTemplate.execute(arg0 -> {
    return null;

6. Listener

Listeners provide additional callbacks on retry. We can use these to focus on individual crosscutting points across different retries.

6.1. Add a callback

The callback is provided in the RetryListener interface:

public class DefaultListenerSupport extends RetryListenerSupport { @Override public <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) { logger.info("onClose"); . super.close(context, callback, throwable); } @Override public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) { logger.info("onError"); . super.onError(context, callback, throwable); } @Override public <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) { logger.info("onOpen"); . return super.open(context, callback); }}

The open and close callbacks are executed before and after the entire retry, while onError is applied to a single RetryCallback call.

6.2. Register the listener

Next, we register our listener (DefaultListenerSupport) with our RetyTemplate bean:

@Configuration public class AppConfig { ... @Bean public RetryTemplate retryTemplate() { RetryTemplate retryTemplate = new RetryTemplate(); . retryTemplate.registerListener(new DefaultListenerSupport()); return retryTemplate; }}

7. Test results

To complete our example, let’s verify the results:

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

From the test log, we can see that we have configured the RetryTemplate and RetryListener correctly:

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

8, conclusion

In this article, we saw how to use an annotation, retryTemplate, and a callback listener to use Spring Retry.

The original address: https://www.baeldung.com/spri…

Code farmers panda

For more technical products, please visit my personal website https://pinmost.com, or pay attention to the public account [Code Panda].