SpringBoot and spring retry example: declarative retry

This example would show you how to use spring retry within springboot applications, Let’s begin.

Spring retry is a module for automatically retry for you, it provides the out-of-box retry functions for ad-hoc method of spring beans.All you need to do is to learn how to declare it.

1. Pom.xml

Here we use jdk1.8, spring boot 1.4.3 and spring retry 1.2.0,here is pom:

<dependencyManagement>
    <dependencies>
        <dependency>
            <!-- Import dependency management from Spring Boot -->
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>1.4.3.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
<dependencies>
	<dependency>
	    <groupId>org.springframework.boot</groupId>
	    <artifactId>spring-boot-starter-aop</artifactId>
	</dependency>
	<dependency>
	    <groupId>org.springframework.retry</groupId>
	    <artifactId>spring-retry</artifactId>
	    <version>1.2.0.RELEASE</version>
	</dependency>
</dependencies>

You can see that we use dependencyManagement to import spring-boot poms and add two dependencies:

  • spring-boot-starter-aop: spring retry use spring aop technologies, so we add it.
  • spring-retry: the core jar, now the stable version is 1.2.0.RELEASE

2. Setup the beans

To demo retry, we must have a method that would probably fail, and because spring retry is based on AOP , it must catch some exception to retry(like transacation), so we also defined an Exception Class.

  • The custome Exception class to be caught by spring-retry
public class MyException extends Exception {
    public MyException(String message) {
        super(message);
    }
}
  • The Service Bean that have a dangerous method for retry
    @Override
    @Retryable(maxAttempts = 3, backoff = @Backoff(delay=2000)) /* line 1 */
    public boolean mayFailedCall() throws MyException {
        mayFailedCallTimes++;
        log.debug("mayFailedCallTimes = "+mayFailedCallTimes);
        if(mayFailedCallTimes>=3) {
            return true;
        }
        throw new MyException("exception "+mayFailedCallTimes);
    }

The above code defines a method which would throw an exception if you call now more than 3 times, if you call it the third time, you can get a true value. This method is to mimic the error-prone network operations.

Line 1 explanation: Here we add an annotation named @Retryable to the method, it means that , this method should be retried if it throws Exceptions, the max attempts is 3 and the retry interval is 2000ms.

  • Add @EnableRetry to @SpringBootApplication
@EnableRetry
@SpringBootApplication
public class MyApp {
    public static void main(String[] args) throws InterruptedException {
        SpringApplication.run(MyApp.class, args);
    }
}

To enable sprint retry, we must add @EnableRetry to the @Configuration bean of your application. For spring boot ,add it on the @SpringBootApplication,which is MyApp.

3. Setup unit tests

  • add unit test jars to pom.xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>
  • write an unit test for @Retryable methods. Here we write a method to call the dangerous method in MyService,it should retry automatically. Here is the test code:
@RunWith(SpringRunner.class)
@SpringBootTest
public class MyServiceTests {
    @Autowired
    private MyService myService;

    @Test
    public void testRetry1() throws MyException {
        assertTrue(myService.mayFailedCall()); /*line 1*/
        assertTrue(myService.getMayFailedCallTimes()==3);/*line 2*/
    }
}

explanations:

  • line 1: here we call the dangerous method “mayFailedCall” ,it should be:
    • first time call: failed
    • second time call: failed
    • third time call: success
  • line 2: To record the total call times , we defined a property named mayFailedCallTimes, here we check if it is equal to 3, because if retry works, then it should be 3

4.Run the tests

Here we run the tests and the core logs are as follows:

1 tests passed.
Started MyServiceTests in 3.733 seconds (JVM running for 8.364)
2017-01-23 16:23:55.051 DEBUG 5928 --- [           main] c.b.retry.service.impls.MyServiceImpl    : mayFailedCallTimes = 1
2017-01-23 16:23:57.055 DEBUG 5928 --- [           main] c.b.retry.service.impls.MyServiceImpl    : mayFailedCallTimes = 2
2017-01-23 16:23:59.055 DEBUG 5928 --- [           main] c.b.retry.service.impls.MyServiceImpl    : mayFailedCallTimes = 3

You can see that the @Retryable method is retried automatically.The retry interval is 2000ms as we configured.

Spring retry is awesome.

You can find detail documents about the springboot and spring retry here:

The above runnable example codes can be found here: