Spring-Retry 模擬支付寶非同步通知商戶
阿新 • • 發佈:2019-01-12
一、依賴匯入。
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
二、service層如下。
import com.hteamtech.callback.common.RetMessage; import org.springframework.retry.RetryException; import org.springframework.retry.annotation.Backoff; import org.springframework.retry.annotation.EnableRetry; import org.springframework.retry.annotation.Retryable; import org.springframework.stereotype.Service; import java.text.SimpleDateFormat; import java.util.Date; /** * @描述 * @建立人 樑XL * @建立時間 2018/12/13 */ @Service @EnableRetry public class TestRetryService { private static final String RES_SUCCESS = "success"; private static final long TIME_UNIT = 1000 * 60; private static final int MAX_ATTEMPTS = 5; @Retryable(value = {RetryException.class, RuntimeException.class}, maxAttempts = MAX_ATTEMPTS, backoff = @Backoff(delay = TIME_UNIT, maxDelay = TIME_UNIT * 6, multiplier = 2)) public void testRetry(RetMessage msg) { // 呼叫商戶的介面 String result = showMsg(); // 列印時間 SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String format = simpleDateFormat.format(new Date()); System.out.println("第" + msg.getTimes() + "次非同步回撥,時間為" + format + ",返回結果為" + result); // 丟擲重試的異常 if (!RES_SUCCESS.equals(result)) { msg.setTimes(msg.getTimes() + 1); msg.setSuccess(false); throw new RetryException("retry failed"); } else { msg.setSuccess(true); } } public String showMsg() { return "false"; } @Recover public void recover(RemoteAccessException e) { logger.info(e.getMessage()); } }
三、執行列印結果。
第1次非同步回撥,時間為2018-12-14 14:44:35,返回結果為false
第2次非同步回撥,時間為2018-12-14 14:45:35,返回結果為false
第3次非同步回撥,時間為2018-12-14 14:47:35,返回結果為false
第4次非同步回撥,時間為2018-12-14 14:51:35,返回結果為false
第5次非同步回撥,時間為2018-12-14 14:57:35,返回結果為false
// 之後便丟擲ReTry異常
四、註解解析
@Retryable
- 被註解的方法發生異常時會重試
- value:指定發生的異常進行重試
- include:和value一樣,預設空,當exclude也為空時,所有異常都重試
- exclude:指定異常不重試,預設空,當include也為空時,所有異常都重試
- maxAttemps:重試次數,預設3
- backoff:重試補償機制,預設沒有
@Backoff
- 延遲策略
- delay:指定延遲後重試
- multiplier:指定延遲的倍數,比如delay=5000l,multiplier=2時,第一次重試為5秒後,第二次為10秒,第三次為20秒
@Recover
- 當重試到達指定次數時,被註解的方法將被回撥,可以在該方法中進行日誌處理。需要注意的是發生的異常和入參型別一致時才會回撥。
五、避坑指南。
- 使用了@Retryable的方法不能再本類內被呼叫,不然重試機制不會生效。也就是要標記為@Service,然後再其他類使用@Autowired 注入或者@Bean去例項化才能生效。
- 要觸發@Recover方法,那麼在@Retryable方法上不能有返回值,只能是void才能生效。
- 使用了@Retryable的方法裡面不能使用try…catch包裹,要丟擲異常,不然不會觸發。
- 在重試期間這個方法是同步的,如果使用類似Spring Cloud這種框架的熔斷機制時,可以結合重試機制來重試後返回結果。
- SpringRetry不只能注入方式去實現,還可以通過API的方式實現,類似熔斷處理的機制就基於API方式實現會比較寬鬆。