In this post under Spring Retry, I will explain with example the purpose of RecoveryCallback.
As you know Spring Retry is used for retrying failed operations hoping that during next attempt the operations completes successfuly.
But some operations never successfuly completes even after retrying multiple times. So in these cases only option left is recover from those failed operation.
So to provide recovery logic we use RecoveryCallback interface.
For our example, we use the below Service1 class.
Service1
public class Service1 {
private int i = 0;
private int j = 0;
public void executeWithException() {
i = i + 1;
System.out.println("Executing method 'executeWithException' : " + i);
throw new NullPointerException();
}
public void executeWithoutException() {
j = j + 1;
System.out.println("Executing method 'executeWithoutException' : " + j);
}
public String recovery() {
return "Recovered";
}
}
The above service class has three methods, “executeWithException” which throws NullPointerException, “executeWithoutException” which doesn’t throw any exception, and “recovery” methods recovers from the exception.
Below is the xml configuration
XML configuration
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="retryTemplate" class="org.springframework.retry.support.RetryTemplate"/>
<bean id="service1" class="Service1"/>
</beans>
We have declared a bean with id “retryTemplate”. The default implementation of RetryTemplate is to retry the failed operations 3 times.
Next we declared a bean for our class “Service1”
Below is the main class
Main Class
1 import org.springframework.context.ApplicationContext;
2 import org.springframework.context.support.ClassPathXmlApplicationContext;
3 import org.springframework.retry.support.RetryTemplate;
4
5 public class Example4 {
6 public static void main(String[] args) {
7 ApplicationContext context = new ClassPathXmlApplicationContext("Example4.xml");
8 Service1 service1 = (Service1)context.getBean("service1");
9 RetryTemplate retryTemplate = (RetryTemplate)context.getBean("retryTemplate");
10
11 try {
12 String result = retryTemplate.execute(retryContext -> { service1.executeWithException(); return null; }, retryContext -> { return service1.recovery(); });
13 System.out.println(result);
14 } catch(Exception excep) {
15 excep.printStackTrace();
16 }
17 }
18 }
In the above java code, at line 12 we are calling “RetryTemplate”‘s “execute” method and passing two lambda functions.
The “execute” method is the overloaded version of RetryTemplate. This version takes two parameters, one being an implementation of “RetryCallback” interface and another being an implementation
of “RecoveryCallback” interface.
The first one being, lambda for the method that will throw exception and which has to be retried.
retryContext -> { service1.executeWithException(); return null; }
The second one being, lambda that includes method call to “recovery” method as shown below
retryContext -> { return service1.recovery(); }
When we execute above main class below is the output that will be generated
Output
[INFO] ClassPathXmlApplicationContext – Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@6576fe71: startup date [Fri Jan 14 15:33:34 IST 2022]; root of context hierarchy
[INFO] XmlBeanDefinitionReader – Loading XML bean definitions from class path resource [Example4.xml]
Executing method ‘executeWithException’ : 1
Executing method ‘executeWithException’ : 2
Executing method ‘executeWithException’ : 3
Recovered
As you can see the method “executeWithException” was retried 3 times when it didn’t completed successfuly, the recovery method was called.
In this way we can use RecoveryCallback interface.