Spring框架中一個有用的小組件之Spring Retry組件詳解
1、概述
Spring Retry 是Spring框架中的一個組件,
它提供了自動重新調(diào)用失敗操作的能力。這在錯誤可能是暫時發(fā)生的(如瞬時網(wǎng)絡(luò)故障)的情況下很有幫助。
在本文中,我們將看到使用Spring Retry的各種方式:注解、RetryTemplate以及回調(diào)。
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
要在應(yīng)用程序中啟用Spring Retry,我們需要將@EnableRetry
注釋添加到我們的@Configuration
類:
@Configuration @EnableRetry public class AppConfig { ... }
4、使用Spring Retry
4.1、@Retryable
而不用恢復(fù)
我們可以使用@Retryable
注解為方法添加重試功能:
@Service public interface MyService { @Retryable(value = RuntimeException.class) void retryService(String sql); }
在這里,當(dāng)拋出RuntimeException時嘗試重試。
根據(jù)@Retryable的默認(rèn)行為,重試最多可能發(fā)生3次,重試之間有1秒的延遲。
4.2、@Retryable
和@Recover
現(xiàn)在讓我們使用@Recover
注解添加一個恢復(fù)方法:
@Service public interface MyService { @Retryable(value = SQLException.class) void retryServiceWithRecovery(String sql) throws SQLException; @Recover void recover(SQLException e, String sql); }
這里,當(dāng)拋出SQLException
時重試會嘗試運行。 當(dāng)@Retryable
方法因指定異常而失敗時,@Recover
注解定義了一個單獨的恢復(fù)方法。
因此,如果retryServiceWithRecovery
方法在三次嘗試之后還是拋出了SQLException
,那么recover()
方法將被調(diào)用。
恢復(fù)處理程序的第一個參數(shù)應(yīng)該是Throwable
類型(可選)和相同的返回類型。其余的參數(shù)按相同順序從失敗方法的參數(shù)列表中填充。
4.3、自定義@Retryable
的行為
為了自定義重試的行為,我們可以使用參數(shù)maxAttempts
和backoff
:
@Service public 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=2 retry.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; }
請注意,我們現(xiàn)在使用的是maxAttemptsExpression
和delayExpression
而不是maxAttempts
和delay
。
5、RetryTemplate
5.1、RetryOperations
Spring Retry提供了RetryOperations
接口,它提供了一組execute()
方法:
public interface RetryOperations { <T> T execute(RetryCallback<T> retryCallback) throws Exception; ... }
execute()
方法的參數(shù)RetryCallback
,是一個接口,可以插入需要在失敗時重試的業(yè)務(wù)邏輯:
public interface RetryCallback<T> { T doWithRetry(RetryContext context) throws Throwable; }
5.2、RetryTemplate
配置
RetryTemplate
是RetryOperations
的一個實現(xiàn)。
讓我們在@Configuration
類中配置一個RetryTemplate
的bean:
@Configuration 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); return retryTemplate; } }
這個RetryPolicy
確定了何時應(yīng)該重試操作。
其中SimpleRetryPolicy
定義了重試的固定次數(shù),另一方面,BackOffPolicy
用于控制重試嘗試之間的回退。
最后,FixedBackOffPolicy
會使重試在繼續(xù)之前暫停一段固定的時間。
5.3、使用RetryTemplate
要使用重試處理來運行代碼,我們可以調(diào)用retryTemplate.execute()
方法:
retryTemplate.execute(new RetryCallback<Void, RuntimeException>() { @Override public Void doWithRetry(RetryContext arg0) { myService.templateRetryService(); ... } });
我們可以使用lambda表達(dá)式代替匿名類:
retryTemplate.execute(arg0 -> { myService.templateRetryService(); return null; });
6、監(jiān)聽器
監(jiān)聽器在重試時提供另外的回調(diào)。我們可以用這些來關(guān)注跨不同重試的各個橫切點。
6.1、添加回調(diào)
回調(diào)在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
的回調(diào)在整個重試之前和之后執(zhí)行,而onError
應(yīng)用于單個RetryCallback
調(diào)用。
6.2、注冊監(jiān)聽器
接下來,我們將我們的監(jiān)聽器(DefaultListenerSupport)
注冊到我們的RetryTemplate
bean:
@Configuration public class AppConfig { ... @Bean public RetryTemplate retryTemplate() { RetryTemplate retryTemplate = new RetryTemplate(); ... retryTemplate.registerListener(new DefaultListenerSupport()); return retryTemplate; } }
7、測試結(jié)果
為了完成我們的示例,讓我們驗證一下結(jié)果:
@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; }); } }
從測試日志中可以看出,我們已經(jīng)正確配置了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、結(jié)論
在本文中,我們看到了如何使用注解、RetryTemplate
和回調(diào)監(jiān)聽器來使用Spring Retry。
原文地址:https://www.baeldung.com/spring-retry
到此這篇關(guān)于Spring框架中一個有用的小組件:Spring Retry的文章就介紹到這了,更多相關(guān)Spring Spring Retry組件內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
RabbitMQ,RocketMQ,Kafka?事務(wù)性,消息丟失,消息順序性和消息重復(fù)發(fā)送的處理策略問題
這篇文章主要介紹了RabbitMQ,RocketMQ,Kafka?事務(wù)性,消息丟失,消息順序性和消息重復(fù)發(fā)送的處理策略,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-03-03Java中如何將list轉(zhuǎn)為樹形結(jié)構(gòu)
這篇文章主要介紹了Java中如何將list轉(zhuǎn)為樹形結(jié)構(gòu),本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-09-09java中@JsonValue和@JsonCreator使用
本文主要介紹了java中@JsonValue和@JsonCreator使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-06-06Jmeter?BlazeMeter實現(xiàn)web錄制過程
BlazeMeter是一款與Apache JMeter兼容的chrome插件,采用BlazeMeter可以方便的進(jìn)行流量錄制和腳本生成,作為接口測試腳本編寫的一個基礎(chǔ),這篇文章主要介紹了Jmeter?BlazeMeter實現(xiàn)web錄制,需要的朋友可以參考下2021-12-12Lombok注解之@SuperBuilder--解決無法builder父類屬性問題
這篇文章主要介紹了Lombok注解之@SuperBuilder--解決無法builder父類屬性問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-09-09淺談SpringBoot中的Bean初始化方法?@PostConstruct
這篇文章主要介紹了SpringBoot中的Bean初始化方法?@PostConstruct,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-11-11