<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
spring-retry是spring提供的一個重試框架,原本自己實現的重試機制,現在spring幫封裝好提供更加好的編碼體驗。
重試的使用場景比較多,比如呼叫遠端服務時,由於網路或者伺服器端響應慢導致呼叫超時,此時可以多重試幾次。用定時任務也可以實現重試的效果,但比較麻煩,用Spring Retry的話一個註解搞定所有。話不多說,先看演示。
首先引入依賴
<dependency> <groupId>org.springframework.retry</groupId> <artifactId>spring-retry</artifactId> <version>1.3.4</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.9.1</version> </dependency>
使用方式有兩種:命令式和宣告式
命令式
/** * 命令式的方式使用Spring Retry */ @GetMapping("/hello") public String hello(@RequestParam("code") Integer code) throws Throwable { RetryTemplate retryTemplate = RetryTemplate.builder() .maxAttempts(3) .fixedBackoff(1000) .retryOn(RemoteAccessException.class) .build(); retryTemplate.registerListener(new MyRetryListener()); String resp = retryTemplate.execute(new RetryCallback<String, Throwable>() { @Override public String doWithRetry(RetryContext context) throws Throwable { return helloService.hello(code); } }); return resp; }
定義一個RetryTemplate,然後呼叫execute方法,可設定項比較多,不一一列舉
真正使用的時候RetryTemplate可以定義成一個Bean,例如:
@Configuration public class RetryConfig { @Bean public RetryTemplate retryTemplate() { RetryTemplate retryTemplate = RetryTemplate.builder() .maxAttempts(3) .fixedBackoff(1000) .withListener(new MyRetryListener()) .retryOn(RemoteAccessException.class) .build(); return retryTemplate; } }
業務程式碼:
/** * 命令式的方式使用Spring Retry */ @Override public String hello(int code) { if (0 == code) { System.out.println("出錯了"); throw new RemoteAccessException("出錯了"); } System.out.println("處理完成"); return "ok"; }
監聽器實現:
package com.example.retry.listener; import org.springframework.retry.RetryCallback; import org.springframework.retry.RetryContext; import org.springframework.retry.RetryListener; public class MyRetryListener implements RetryListener { @Override public <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) { System.out.println("open"); return true; } @Override public <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) { System.out.println("close"); } @Override public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) { System.out.println("error"); } }
宣告式(註解方式)
/** * 註解的方式使用Spring Retry */ @Retryable(value = Exception.class, maxAttempts = 2, backoff = @Backoff(value = 1000, delay = 2000, multiplier = 0.5)) @Override public String hi(int code) { System.out.println("方法被呼叫"); int a = 1/code; return "ok"; } @Recover public String hiRecover(Exception ex, int code) { System.out.println("重試結束"); return "asdf"; }
這裡需要主要的幾點
/** * 註解的方式使用Spring Retry */ @GetMapping("/hi") public String hi(@RequestParam("code") Integer code) { return helloService.hi(code); }
宣告式
@Configuration @EnableRetry public class Application { } @Service class Service { @Retryable(RemoteAccessException.class) public void service() { // ... do something } @Recover public void recover(RemoteAccessException e) { // ... panic } }
命令式
RetryTemplate template = RetryTemplate.builder() .maxAttempts(3) .fixedBackoff(1000) .retryOn(RemoteAccessException.class) .build(); template.execute(ctx -> { // ... do something });
為了自動重試,Spring Retry 提供了 RetryOperations 重試操作策略
public interface RetryOperations { <T> T execute(RetryCallback<T> retryCallback) throws Exception; <T> T execute(RetryCallback<T> retryCallback, RecoveryCallback<T> recoveryCallback) throws Exception; <T> T execute(RetryCallback<T> retryCallback, RetryState retryState) throws Exception, ExhaustedRetryException; <T> T execute(RetryCallback<T> retryCallback, RecoveryCallback<T> recoveryCallback, RetryState retryState) throws Exception; }
基本回撥是一個簡單的介面,允許插入一些要重試的業務邏輯:
public interface RetryCallback<T> { T doWithRetry(RetryContext context) throws Throwable; }
回撥函數被嘗試,如果失敗(通過丟擲異常),它將被重試,直到成功或實現決定中止。
RetryOperations最簡單的通用實現是RetryTemplate
RetryTemplate template = new RetryTemplate(); TimeoutRetryPolicy policy = new TimeoutRetryPolicy(); policy.setTimeout(30000L); template.setRetryPolicy(policy); Foo result = template.execute(new RetryCallback<Foo>() { public Foo doWithRetry(RetryContext context) { // Do stuff that might fail, e.g. webservice operation return result; } });
從Spring Retry 1.3開始,RetryTemplate支援流式設定:
RetryTemplate.builder() .maxAttempts(10) .exponentialBackoff(100, 2, 10000) .retryOn(IOException.class) .traversingCauses() .build(); RetryTemplate.builder() .fixedBackoff(10) .withinMillis(3000) .build(); RetryTemplate.builder() .infiniteRetry() .retryOn(IOException.class) .uniformRandomBackoff(1000, 3000) .build();
當重試耗盡時,RetryOperations可以將控制傳遞給不同的回撥:RecoveryCallback。
Foo foo = template.execute(new RetryCallback<Foo>() { public Foo doWithRetry(RetryContext context) { // business logic here }, new RecoveryCallback<Foo>() { Foo recover(RetryContext context) throws Exception { // recover logic here } });
public interface RetryListener { void open(RetryContext context, RetryCallback<T> callback); void onSuccess(RetryContext context, T result); void onError(RetryContext context, RetryCallback<T> callback, Throwable e); void close(RetryContext context, RetryCallback<T> callback, Throwable e); }
在最簡單的情況下,open和close回撥在整個重試之前和之後,onSuccess和onError應用於個別的RetryCallback呼叫,onSuccess方法在成功呼叫回撥之後被呼叫。
有時,你希望在每次業務處理髮生時都重試一些業務處理。這方面的典型例子是遠端服務呼叫。Spring Retry提供了一個AOP攔截器,它將方法呼叫封裝在RetryOperations範例中。RetryOperationsInterceptor執行被攔截的方法,並根據提供的RepeatTemplate中的RetryPolicy在失敗時重試。
你可以在 @Configuration 類上新增一個 @EnableRetry 註解,並且在你想要進行重試的方法(或者類)上新增 @Retryable 註解,還可以指定任意數量的重試監聽器。
@Configuration @EnableRetry public class Application { @Bean public Service service() { return new Service(); } @Bean public RetryListener retryListener1() { return new RetryListener() {...} } @Bean public RetryListener retryListener2() { return new RetryListener() {...} } } @Service class Service { @Retryable(RemoteAccessException.class) public service() { // ... do something } }
可以使用 @Retryable 的屬性類控制 RetryPolicy 和 BackoffPolicy
@Service class Service { @Retryable(maxAttempts=12, backoff=@Backoff(delay=100, maxDelay=500)) public service() { // ... do something } }
如果希望在重試用盡時採用替代程式碼返回,則可以提供恢復方法。方法應該宣告在與@Retryable範例相同的類中,並標記為@Recover。返回型別必須匹配@Retryable方法。恢復方法的引數可以包括丟擲的異常和(可選地)傳遞給原始可重試方法的引數(或者它們的部分列表,只要在需要的最後一個之前不省略任何引數)。
@Service class Service { @Retryable(RemoteAccessException.class) public void service(String str1, String str2) { // ... do something } @Recover public void recover(RemoteAccessException e, String str1, String str2) { // ... error handling making use of original args if required } }
若要解決可選擇用於恢復的多個方法之間的衝突,可以顯式指定恢復方法名稱。
@Service class Service { @Retryable(recover = "service1Recover", value = RemoteAccessException.class) public void service1(String str1, String str2) { // ... do something } @Retryable(recover = "service2Recover", value = RemoteAccessException.class) public void service2(String str1, String str2) { // ... do something } @Recover public void service1Recover(RemoteAccessException e, String str1, String str2) { // ... error handling making use of original args if required } @Recover public void service2Recover(RemoteAccessException e, String str1, String str2) { // ... error handling making use of original args if required } }
https://github.com/spring-projects/spring-retry
到此這篇關於Spring Retry 重試的文章就介紹到這了,更多相關Spring Retry 重試內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45