In this post under Spring Retry, I will show with example how to add RetryListener to our Spring Retry code.
RetryListener interface will help us to react to events like (react before first retry attempt, react after every failed retry attempt, react after final retry attempt).
RetryListener interface has the below three interface methods.
1) void open(RetryContext context, RetryCallback callback)
–> Called before the first attempt in a retry.
2) void onError(RetryContext context, RetryCallback callback, Throwable throwable)
–> Called after every unsuccessful attempt at a retry.
3) boolean close(RetryContext context, RetryCallback callback, Throwable throwable)
–> Called after the final attempt (successful or not).
For this example we will use the below service 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 "Hello";
}
}
We will create a class “CustomRetryListener1” which implements the “RetryListener” interface. Below is the code for the class
CustomRetryListener1
import org.springframework.retry.RetryCallback;
import org.springframework.retry.RetryContext;
import org.springframework.retry.RetryListener;
public class CustomRetryListener1 implements RetryListener {
@Override
public <T, E extends Throwable> void close(RetryContext arg0, RetryCallback<T, E> arg1, Throwable arg2) {
System.out.println("Calling 'close' method");
}
@Override
public <T, E extends Throwable> void onError(RetryContext arg0, RetryCallback<T, E> arg1, Throwable arg2) {
System.out.println("Calling 'onError' method");
}
@Override
public <T, E extends Throwable> boolean open(RetryContext arg0, RetryCallback<T, E> arg1) {
System.out.println("Calling 'open' method");
return true;
}
}
Please note the “open” method must return a boolean. If “true” is returned, retry attempt will proceed as usual otherwise the retry attempt is aborted.
Next I will show how to add the listener to RetryTemplate using xml configuration
XML
1 <xml version="1.0" encoding="UTF-8"/>
2 <beans xmlns="http://www.springframework.org/schema/beans"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd>
5 <bean id="customRetryListener" class="CustomRetryListener1"/>
6
7 <bean id="retryTemplate" class="org.springframework.retry.support.RetryTemplate">
8 <property name="listeners">
9 <list>
10 <ref bean="customRetryListener"/>
11 </list>
12 </property>
13 </bean>
14
15 <bean id="service1" class="Service1">
16 </beans>
In the above xml code, at line 5, I have created a bean definition for our “CustomRetryListener1”
From line 7 to 13, we create a “RetryTemplate” bean with the listener created at line 5 added in “RetryTemplate’s” “listeners” property.
At line 15, I create a bean definition for our “Service1” class.
In this way we configure “RetryTemplate” instance to use “CustomRetryListener1” listener
Below is the main class for your reference
Main
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.retry.support.RetryTemplate;
public class Example2 {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("Example2.xml");
Service1 service1 = (Service1)context.getBean("service1");
RetryTemplate retryTemplate = (RetryTemplate)context.getBean("retryTemplate");
retryTemplate.execute(retryContext -> { service1.executeWithException(); return null; });
}
}
Output
[INFO] ClassPathXmlApplicationContext – Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@6576fe71: startup date [Sat Nov 27 10:45:48 IST 2021]; root of context hierarchy
[INFO] XmlBeanDefinitionReader – Loading XML bean definitions from class path resource [Example2.xml]
Calling ‘open’ method
Executing method ‘executeWithException’ : 1
Calling ‘onError’ method
Executing method ‘executeWithException’ : 2
Calling ‘onError’ method
Executing method ‘executeWithException’ : 3
Calling ‘onError’ method
Exception in thread “main” java.lang.NullPointerException
at Service1.executeWithException(Service1.java:8)
at Example2.lambda$0(Example2.java:11)
at org.springframework.retry.support.RetryTemplate.doExecute(RetryTemplate.java:329)
at org.springframework.retry.support.RetryTemplate.execute(RetryTemplate.java:209)
at Example2.main(Example2.java:11)
Calling ‘close’ method