請求重試,異常重試

需求:夜間定時任務比較多,偶爾遇到請求超時的情況,也可能是網絡波動,總之需要做請求失敗重試。

1,引入spring-retry註解

    <dependency>
        <groupId>org.springframework.retry</groupId>
        <artifactId>spring-retry</artifactId>
        <version>1.2.2.RELEASE</version>
    </dependency>

2,啓動類開啓重試註解掃描

@SpringBootApplication
@EnableRetry
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

3,業務類添加@Retryable

package com.example.demo.service;

import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.remoting.RemoteAccessException;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Random;

@Service
public class Testservice {

    @Retryable(value = {RemoteAccessException.class} ,backoff = @Backoff(delay = 3000l, multiplier = 0))
    public void main(){
            System.out.println("-----------發起請求");
//            String url = "http://127.0.0.1:8100/api/materials-product/updateRedis";
//            String res = requestByGetMethod(url);
//            JSONObject jo = JSONObject.parseObject(res);
//            int a = Integer.parseInt(jo.get("data").toString());

            //生成0~10之間的隨機數
            Random r = new Random();
            int a = r.nextInt(5);   
            if (a > 2) {
                System.out.println("請求超時");
                throw new RemoteAccessException("請求超時或中斷");
            } else {
                System.out.println("---------請求成功");
            }
    }


    @Recover()
    public void backroll(RemoteAccessException e){
        System.out.println("----->重試失敗執行回調" + e.toString());
    }
    
    //真實遠程連接
    public static String requestByGetMethod(String url) {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        StringBuilder entityStringBuilder = null;
        try {
            HttpPost get = new HttpPost(url);
            CloseableHttpResponse httpResponse = null;
            httpResponse = httpClient.execute(get);
            try {
                HttpEntity entity = httpResponse.getEntity();
                entityStringBuilder = new StringBuilder();
                if (null != entity) {
                    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(httpResponse.getEntity().getContent(), "UTF-8"), 8 * 1024);
                    String line = null;
                    while ((line = bufferedReader.readLine()) != null) {
                        entityStringBuilder.append(line);
                    }
                }
            } finally {
                httpResponse.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (httpClient != null) {
                    httpClient.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return entityStringBuilder.toString();
    }
}

4,運行測試

因爲請求超時和網絡中斷情況不方便模擬,以上代碼先通過隨機數本地模擬請求失敗的情況。 需要寫一個簡單的控制器不斷髮起請求。

@RestController
public class testController {
    @Autowired
    private Testservice testservice;
    
    @PostMapping("test")
    public String updateRedis() {
        testservice.main();
        return "已發送";
    }
}

4,運行測試

---------請求成功
-----------發起請求
---------請求成功
-----------發起請求
---------請求成功
-----------發起請求
請求超時
-----------發起請求
請求超時
-----------發起請求
請求超時
----->重試失敗執行回調org.springframework.remoting.RemoteAccessException: 請求超時或中斷

5,註解詳解

1.@Retryable參數的說明
  • value:拋出指定異常纔會重試
  • include:和value一樣,默認爲空,當exclude也爲空時,默認所以異常
  • exclude:指定不處理的異常
  • maxAttempts:最大重試次數,默認3次
  • backoff:重試等待策略,默認使用@Backoff,@Backoff的value默認爲1000L,我們設置爲2000L;multiplier(指定延遲倍數)默認爲0,表示固定暫停1秒後進行重試,如果把multiplier設置爲1.5,則第一次重試爲2秒,第二次爲3秒,第三次爲4.5秒。
2.@Recover註解

當重試耗盡時,RetryOperations可以將控制傳遞給另一個回調,用於@Retryable重試失敗後處理方法,此方法裏的異常一定要是@Retryable方法裏拋出的異常,否則不會調用這個方法。

3.注意

使用了@Retryable的方法在本類中使用沒有效果,只有在其他類中使用@Autowired注入或者@Bean才能生效。
 要觸發@Recover方法,@Retryable方法不能存在返回值,只能是void
 使用@Retryable的方法裏不能使用try catch包裹,要在方法上拋出異常,不然不會觸發

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章