Spring框架中一個有用的小組件之Spring Retry組件詳解
Spring Retry 是Spring框架中的一個組件,它提供了自動重新調用失敗操作的能力。這在錯誤可能是暫時發生的(如瞬時網絡故障)的情況下很有幫助。
在本文中,我們將看到使用Spring Retry的各種方式:注解、RetryTemplate以及回調。
2、Maven依賴讓我們首先將spring-retry依賴項添加到我們的pom.xml文件中:
<dependency> <groupId>org.springframework.retry</groupId> <artifactId>spring-retry</artifactId> <version>1.2.5.RELEASE</version></dependency>
我們還需要將Spring AOP添加到我們的項目中:
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>5.2.8.RELEASE</version></dependency>
可以查看Maven Central來獲取最新版本的spring-retry和spring-aspects 依賴項。
3、開啟Spring Retry要在應用程序中啟用Spring Retry,我們需要將@EnableRetry注釋添加到我們的@Configuration類:
@Configuration@EnableRetrypublic class AppConfig { ... }4、使用Spring Retry
4.1、@Retryable而不用恢復
我們可以使用@Retryable注解為方法添加重試功能:
@Servicepublic interface MyService { @Retryable(value = RuntimeException.class) void retryService(String sql);}
在這里,當拋出RuntimeException時嘗試重試。
根據@Retryable的默認行為,重試最多可能發生3次,重試之間有1秒的延遲。
4.2、@Retryable和@Recover
現在讓我們使用@Recover注解添加一個恢復方法:
@Servicepublic interface MyService { @Retryable(value = SQLException.class) void retryServiceWithRecovery(String sql) throws SQLException; @Recover void recover(SQLException e, String sql);}
這里,當拋出SQLException時重試會嘗試運行。 當@Retryable方法因指定異常而失敗時,@Recover注解定義了一個單獨的恢復方法。
因此,如果retryServiceWithRecovery方法在三次嘗試之后還是拋出了SQLException,那么recover()方法將被調用。
恢復處理程序的第一個參數應該是Throwable類型(可選)和相同的返回類型。其余的參數按相同順序從失敗方法的參數列表中填充。
4.3、自定義@Retryable的行為
為了自定義重試的行為,我們可以使用參數maxAttempts和backoff:
@Servicepublic interface MyService { @Retryable( value = SQLException.class, maxAttempts = 2, backoff = @Backoff(delay = 100)) void retryServiceWithCustomization(String sql) throws SQLException;}
這樣最多將有兩次嘗試和100毫秒的延遲。
4.4、使用Spring Properties
我們還可以在@Retryable注解中使用properties。
為了演示這一點,我們將看到如何將delay和maxAttempts的值外部化到一個properties文件中。
首先,讓我們在名為retryConfig.properties的文件中定義屬性:
retry.maxAttempts=2retry.maxDelay=100
然后我們指示@Configuration類加載這個文件:
@PropertySource('classpath:retryConfig.properties')public class AppConfig { ... }// ...
最后,我們可以在@Retryable的定義中注入retry.maxAttempts和retry.maxDelay的值:
@Service public interface MyService { @Retryable( value = SQLException.class, maxAttemptsExpression = '${retry.maxAttempts}', backoff = @Backoff(delayExpression = '${retry.maxDelay}')) void retryServiceWithExternalizedConfiguration(String sql) throws SQLException; }
請注意,我們現在使用的是maxAttemptsExpression和delayExpression而不是maxAttempts和delay。
5、RetryTemplate5.1、RetryOperations
Spring Retry提供了RetryOperations接口,它提供了一組execute()方法:
public interface RetryOperations { <T> T execute(RetryCallback<T> retryCallback) throws Exception; ...}
execute()方法的參數RetryCallback,是一個接口,可以插入需要在失敗時重試的業務邏輯:
public interface RetryCallback<T> { T doWithRetry(RetryContext context) throws Throwable;}
5.2、RetryTemplate配置
RetryTemplate是RetryOperations的一個實現。
讓我們在@Configuration類中配置一個RetryTemplate的bean:
@Configurationpublic 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; }}
這個RetryPolicy確定了何時應該重試操作。
其中SimpleRetryPolicy定義了重試的固定次數,另一方面,BackOffPolicy用于控制重試嘗試之間的回退。
最后,FixedBackOffPolicy會使重試在繼續之前暫停一段固定的時間。
5.3、使用RetryTemplate
要使用重試處理來運行代碼,我們可以調用retryTemplate.execute()方法:
retryTemplate.execute(new RetryCallback<Void, RuntimeException>() { @Override public Void doWithRetry(RetryContext arg0) {myService.templateRetryService();... }});
我們可以使用lambda表達式代替匿名類:
retryTemplate.execute(arg0 -> { myService.templateRetryService(); return null;});6、監聽器
監聽器在重試時提供另外的回調。我們可以用這些來關注跨不同重試的各個橫切點。
6.1、添加回調
回調在RetryListener接口中提供:
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); }}
open和close的回調在整個重試之前和之后執行,而onError應用于單個RetryCallback調用。
6.2、注冊監聽器
接下來,我們將我們的監聽器(DefaultListenerSupport)注冊到我們的RetryTemplate bean:
@Configurationpublic class AppConfig { ... @Bean public RetryTemplate retryTemplate() {RetryTemplate retryTemplate = new RetryTemplate();...retryTemplate.registerListener(new DefaultListenerSupport());return retryTemplate; }}7、測試結果
為了完成我們的示例,讓我們驗證一下結果:
@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;}); }}
從測試日志中可以看出,我們已經正確配置了RetryTemplate和RetryListener:
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、結論在本文中,我們看到了如何使用注解、RetryTemplate和回調監聽器來使用Spring Retry。
原文地址:https://www.baeldung.com/spring-retry
到此這篇關于Spring框架中一個有用的小組件:Spring Retry的文章就介紹到這了,更多相關Spring Spring Retry組件內容請搜索好吧啦網以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持好吧啦網!
相關文章:
