From 8734c956bb5ce53619f1a330f20c4a8a21bb8054 Mon Sep 17 00:00:00 2001 From: Tuan Date: Fri, 13 Jan 2017 13:53:59 +0700 Subject: [PATCH] BAEL-470-Spring Retry (#967) * add Spring Retry * remove redundant code * convert tab to space in XML file * align spaces in xml file --- spring-all/pom.xml | 7 ++- .../org/baeldung/springretry/AppConfig.java | 34 +++++++++++++ .../springretry/DefaultListenerSupport.java | 31 ++++++++++++ .../org/baeldung/springretry/MyService.java | 21 ++++++++ .../baeldung/springretry/MyServiceImpl.java | 39 +++++++++++++++ spring-all/src/main/resources/retryadvice.xml | 50 +++++++++++++++++++ .../baeldung/springretry/SpringRetryTest.java | 45 +++++++++++++++++ 7 files changed, 226 insertions(+), 1 deletion(-) create mode 100644 spring-all/src/main/java/org/baeldung/springretry/AppConfig.java create mode 100644 spring-all/src/main/java/org/baeldung/springretry/DefaultListenerSupport.java create mode 100644 spring-all/src/main/java/org/baeldung/springretry/MyService.java create mode 100644 spring-all/src/main/java/org/baeldung/springretry/MyServiceImpl.java create mode 100644 spring-all/src/main/resources/retryadvice.xml create mode 100644 spring-all/src/test/java/org/baeldung/springretry/SpringRetryTest.java diff --git a/spring-all/pom.xml b/spring-all/pom.xml index e77bf0b284..deb6bd6f6a 100644 --- a/spring-all/pom.xml +++ b/spring-all/pom.xml @@ -38,6 +38,11 @@ org.springframework spring-context + + org.springframework.retry + spring-retry + ${springretry.version} + @@ -166,7 +171,6 @@ ehcache ${ehcache.version} - @@ -275,6 +279,7 @@ 4.3.4.RELEASE 4.2.0.RELEASE + 1.1.5.RELEASE 5.2.5.Final diff --git a/spring-all/src/main/java/org/baeldung/springretry/AppConfig.java b/spring-all/src/main/java/org/baeldung/springretry/AppConfig.java new file mode 100644 index 0000000000..63bb2a53f1 --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/springretry/AppConfig.java @@ -0,0 +1,34 @@ +package org.baeldung.springretry; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.retry.annotation.EnableRetry; +import org.springframework.retry.backoff.FixedBackOffPolicy; +import org.springframework.retry.policy.SimpleRetryPolicy; +import org.springframework.retry.support.RetryTemplate; + +@Configuration +@ComponentScan(basePackages = "org.baeldung.springretry") +@EnableRetry +//Uncomment this two lines if we need XML configuration +//@EnableAspectJAutoProxy +//@ImportResource("classpath:/retryadvice.xml") +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); + + retryTemplate.registerListener(new DefaultListenerSupport()); + return retryTemplate; + } +} diff --git a/spring-all/src/main/java/org/baeldung/springretry/DefaultListenerSupport.java b/spring-all/src/main/java/org/baeldung/springretry/DefaultListenerSupport.java new file mode 100644 index 0000000000..bc251b4c2f --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/springretry/DefaultListenerSupport.java @@ -0,0 +1,31 @@ +package org.baeldung.springretry; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.retry.RetryCallback; +import org.springframework.retry.RetryContext; +import org.springframework.retry.listener.RetryListenerSupport; + +public class DefaultListenerSupport extends RetryListenerSupport { + + private static final Logger logger = LoggerFactory.getLogger(DefaultListenerSupport.class); + + @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); + } + +} diff --git a/spring-all/src/main/java/org/baeldung/springretry/MyService.java b/spring-all/src/main/java/org/baeldung/springretry/MyService.java new file mode 100644 index 0000000000..2b8cc16eb3 --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/springretry/MyService.java @@ -0,0 +1,21 @@ +package org.baeldung.springretry; + +import java.sql.SQLException; + +import org.springframework.retry.annotation.Backoff; +import org.springframework.retry.annotation.Recover; +import org.springframework.retry.annotation.Retryable; + +public interface MyService { + + @Retryable + void retryService(); + + @Retryable(value = { SQLException.class }, maxAttempts = 2, backoff = @Backoff(delay = 5000)) + void retryServiceWithRecovery(String sql) throws SQLException; + + @Recover + void recover(SQLException e, String sql); + + void templateRetryService(); +} diff --git a/spring-all/src/main/java/org/baeldung/springretry/MyServiceImpl.java b/spring-all/src/main/java/org/baeldung/springretry/MyServiceImpl.java new file mode 100644 index 0000000000..1b698f26c9 --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/springretry/MyServiceImpl.java @@ -0,0 +1,39 @@ +package org.baeldung.springretry; + +import java.sql.SQLException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; + +@Service +public class MyServiceImpl implements MyService { + + private static final Logger logger = LoggerFactory.getLogger(MyServiceImpl.class); + + @Override + public void retryService() { + logger.info("throw RuntimeException in method retryService()"); + throw new RuntimeException(); + } + + @Override + public void retryServiceWithRecovery(String sql) throws SQLException { + if (StringUtils.isEmpty(sql)) { + logger.info("throw SQLException in method retryServiceWithRecovery()"); + throw new SQLException(); + } + } + + @Override + public void recover(SQLException e, String sql) { + logger.info("In recover method"); + } + + @Override + public void templateRetryService() { + logger.info("throw RuntimeException in method templateRetryService()"); + throw new RuntimeException(); + } +} diff --git a/spring-all/src/main/resources/retryadvice.xml b/spring-all/src/main/resources/retryadvice.xml new file mode 100644 index 0000000000..8de7801a58 --- /dev/null +++ b/spring-all/src/main/resources/retryadvice.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Initial sleep interval value, default 300 ms + + + + + The maximum value of the backoff period in milliseconds. + + + + + The value to increment the exp seed with for each retry attempt. + + + + + \ No newline at end of file diff --git a/spring-all/src/test/java/org/baeldung/springretry/SpringRetryTest.java b/spring-all/src/test/java/org/baeldung/springretry/SpringRetryTest.java new file mode 100644 index 0000000000..52f59dc49a --- /dev/null +++ b/spring-all/src/test/java/org/baeldung/springretry/SpringRetryTest.java @@ -0,0 +1,45 @@ +package org.baeldung.springretry; + +import java.sql.SQLException; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.retry.RetryCallback; +import org.springframework.retry.RetryContext; +import org.springframework.retry.support.RetryTemplate; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.support.AnnotationConfigContextLoader; + +@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 givenRetryService_whenCallWithException_thenRetry() { + myService.retryService(); + } + + @Test + public void givenRetryServiceWithRecovery_whenCallWithException_thenRetryRecover() throws SQLException { + myService.retryServiceWithRecovery(null); + } + + @Test(expected = RuntimeException.class) + public void givenTemplateRetryService_whenCallWithException_thenRetry() { + retryTemplate.execute(new RetryCallback() { + @Override + public Void doWithRetry(RetryContext arg0) { + myService.templateRetryService(); + return null; + } + }); + } +}