最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java中HTTP接口請求重試的實現(xiàn)方式

 更新時間:2024年01月04日 09:07:17   作者:有一只柴犬  
HTTP接口請求重試是指在請求失敗時,再次發(fā)起請求的機制,在實際應用中,由于網(wǎng)絡波動、服務器故障等原因,HTTP接口請求可能會失敗,為了保證系統(tǒng)的可用性和穩(wěn)定性,需要對HTTP接口請求進行重試,所以本文給大家介紹了HTTP接口請求重試的實現(xiàn)方式,需要的朋友可以參考下

1、前言

HTTP接口請求重試是指在請求失敗時,再次發(fā)起請求的機制。在實際應用中,由于網(wǎng)絡波動、服務器故障等原因,HTTP接口請求可能會失敗。為了保證系統(tǒng)的可用性和穩(wěn)定性,需要對HTTP接口請求進行重試。

2、實現(xiàn)方式

今天給大家分享一些常見的接口請求重試的方式。本地模擬了一個請求接口,后面的代碼示例均模擬請求該接口:

@GetMapping("http_test")
public String getHttpTest(){
    return "接口請求成功,返回:OK";
}

2.1、循環(huán)重試

循環(huán)重試是最簡單最粗暴的方式,就是在請求接口代碼中加入循環(huán)機制,如果接口請求失敗,則循環(huán)繼續(xù)發(fā)起接口請求,直到請求成功或接口重試次數(shù)達到上限。如果請求成功,則不進行重試。

簡單代碼示例如下:

@GetMapping("retry_demo_loop")
public String retry_demo_loop(){
    // 重試上限次數(shù)為3次
    int maxRetryTime = 3;
    String result = null;
    // 接口循環(huán)請求
    for (int i = 1; i <= maxRetryTime; i++) {
        try {
            // 模擬請求接口
            result = HttpUtil.get("http://localhost:8080/http_test");
            // 模擬一次請求失敗
            if(i == 1){
                int co = i / 0;
            }
            // 請求成功,跳出循環(huán)
            break;
        } catch (Exception e) {
            log.error("接口請求異常,進行第{}次重試", i);
            result = "接口請求失敗,請聯(lián)系管理員";
        }
    }
    return result;
}

請求結(jié)果:

重試日志打?。?/p>

2.2、遞歸重試

除了循環(huán),還可以使用遞歸來實現(xiàn)接口的請求重試。遞歸是我們都比較熟悉的編程技巧,在請求接口的方法中調(diào)用自身,如果請求失敗則繼續(xù)調(diào)用,直到請求成功或達到最大重試次數(shù)。

@GetMapping("retry_demo_rec")
public String retry_demo_rec(){
    // 重試上限次數(shù)為3次
    int maxRetryTime = 3;
    return retryRequest(maxRetryTime);
}
 
/**
 * 遞歸方法
 * @param maxRetryTime
 * @return
 */
private String retryRequest(int maxRetryTime){
    if (maxRetryTime <= 0) {
        return "接口請求失敗,請聯(lián)系管理員";
    }
 
    int retryTime = 0;
    try {
        // 模擬請求接口
        String result = HttpUtil.get("http://localhost:8080/http_test");
        // 模擬一次請求失敗
        if(maxRetryTime == 3){
            int co = 1 / 0;
        }
        return result;
    } catch (Exception e) {
        // 處理異常
        log.error("接口請求異常,進行第{}次重試", ++retryTime);
        return retryRequest(maxRetryTime - 1);
    }
}

請求結(jié)果:

重試日志打?。?/p>

2.3、Spring Retry

第三種便是使用Spring Retry依賴實現(xiàn)。首先我們需要集成相關依賴:

<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
</dependency>
<!-- 由于retry使用到了aop,所以還需要加入aop依賴 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

加入@EnableRetry啟動:

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

添加retry方法注解:

public interface MyRetryService {
 
    /**
     * retryable注解表示該方法需要重試
     * value:出現(xiàn)該指定異常后,進行重試
     * maxAttempts:重試次數(shù)上限,這里指定為3次
     * backoff:重試策略,這里指定200ms間隔一次
     * @param code
     * @return
     * @throws Exception
     */
    @Retryable(value = {Exception.class}, maxAttempts = 3, backoff = @Backoff(200))
    String retry(int code) throws Exception;
 
 
    /**
     * 當重試達到上限后還是失敗,則作為異?;卣{(diào)方法
     * @param th
     * @param code
     * @return
     */
    @Recover
    String recover(Throwable th, int code);
 
}

MyReretService實現(xiàn)類:

@Slf4j
@Service
public class MyRetryServiceImpl implements MyRetryService {
 
    @Override
    public String retry(int code) throws Exception {
        log.info("請求retry接口");
        String result = HttpUtil.get("http://localhost:8080/http_test");
        if(code != 200){
            throw new Exception("接口請求異常");
        }
 
        return result;
    }
 
    @Override
    public String recover(Throwable th, int code) {
        log.error("回調(diào)方法執(zhí)行!?。?!");
        return "異常碼為:" + code + ",異常信息:" + th.getMessage();
    }
}

Controller:

@Autowired
private MyRetryService myRetryService;
 
 
/**
 * 當請求code參數(shù)為200時,直接成功
 * 當code參數(shù)!=200時,會出發(fā)重試
 * @param code
 * @return
 * @throws Exception
 */
@GetMapping("retry_demo_spring_retry")
public String retry_demo_spring_retry(Integer code) throws Exception {
    return myRetryService.retry(code);
}

訪問地址:http://localhost:8080/retry_demo_spring_retry?code=123

查看結(jié)果:可以看到接口重試了3次,最后執(zhí)行了@Recover方法最后的回調(diào)。

2.4、Resilience4j

Resilience4j是一個輕量級、易于使用的輕量級“容錯”包。它受Neflix Hystrix啟發(fā)但只有一個依賴(Vavr),而不像Hystrix很多很多的依賴。同時它是一個 Java 庫,可以幫助我們構(gòu)建彈性和容錯的應用程序。Resilience4j在“容錯”方面提供了各種模式:斷路器(Circuit Breaker)、重試(Retry)、限時器(Time Limiter)、限流器(Rate Limiter)、隔板(BulkHead)。我們今天討論的話題是重試,那么今天就來演示下Retry。

Github地址:GitHub - resilience4j/resilience4j: Resilience4j is a fault tolerance library designed for Java8 and functional programming

首先,添加相應依賴:

<dependency>
    <groupId>io.github.resilience4j</groupId>
    <artifactId>resilience4j-spring-boot2</artifactId>
    <version>2.1.0</version>
</dependency>

application.yml配置相關策略,配置官方文檔:https://resilience4j.readme.io/docs/retry

resilience4j:
  retry:
    instances:
      retry_demo:
        max-attempts: 3     # 重試的上限次數(shù)
        wait-duration: 1s   # 重試的間隔時間,配置為1s

我們改造一下上面spring-retry的demo。

controller:

@GetMapping("retry_demo_spring_retry")
@Retry(name = "retry_demo", fallbackMethod = "recover")
public String retry_demo_spring_retry(Integer code) throws Exception {
    return myRetryService.retry(code);
}
 
public String recover(Throwable th) {
    log.error("回調(diào)方法執(zhí)行?。。?!");
    return "異常信息:" + th.getMessage();
}

myRetryService:

@Override
public String retry(int code) throws Exception {
    log.info("請求retry接口");
    String result = HttpUtil.get("http://localhost:8080/http_test");
    if(code != 200){
        throw new Exception("接口請求異常");
    }
    return result;
}

程序執(zhí)行,打印結(jié)果:

同樣接口請求了3次,均失敗后執(zhí)行了fallback回調(diào)方法。

2.5、http請求網(wǎng)絡工具內(nèi)置重試方式

通常一些外部的http網(wǎng)絡工具,都會內(nèi)置一些重試的策略。如Apache HttpClient。這里以httpclient5為例。

首先添加依賴:

<dependency>
    <groupId>org.apache.httpcomponents.client5</groupId>
    <artifactId>httpclient5</artifactId>
    <version>5.1.4</version>
</dependency>

定義HttpClient相關類,指定重試策略。可以使用默認的DefaultHttpRequestRetryStrategy,也可以自定義重試策略CustomRetryStrategy。

private static volatile CloseableHttpClient HTTP_CLIENT = null;
    static {
        if(HTTP_CLIENT == null){
            synchronized (HelloWorldController.class) {
                if(HTTP_CLIENT == null){
                    HTTP_CLIENT = HttpClients.custom()
                            // 設置重試策略
//                            .setRetryStrategy(new DefaultHttpRequestRetryStrategy(3, TimeValue.NEG_ONE_SECOND))
                            // 自定義重試策略
                            .setRetryStrategy(new CustomRetryStrategy())
                            .build();
                }
            }
        }
    }

CustomRetryStrategy:

public static class CustomRetryStrategy implements HttpRequestRetryStrategy {
 
    @Override
    public boolean retryRequest(HttpRequest httpRequest, IOException e, int executeCount, HttpContext httpContext) {
        return false;
    }
 
    @Override
    public boolean retryRequest(HttpResponse httpResponse, int executeCount, HttpContext httpContext) {
        System.out.println("進入重試策略");
        if(executeCount > 3){
            System.out.println("重試超過3次,終止重試");
            return false;
        }
 
        if(httpResponse.getCode() != 200){
            System.out.println("http狀態(tài)碼不等于200,進行重試");
            return true;
        }
 
        // 其他情況,不重試
        return false;
    }
 
    @Override
    public TimeValue getRetryInterval(HttpResponse httpResponse, int executeCount, HttpContext httpContext) {
        return null;
    }
}

Controller代碼:

@GetMapping("retry_demo_httpclient")
public String retry_demo_httpclient(Integer code) throws Exception {
    return httpclientRetry(code);
}
 
private String httpclientRetry(int code) throws Exception {
    log.info("請求retry接口");
    // 這里模擬了一個不存在的地址
    HttpGet request = new HttpGet("http://localhost:8080/http_test1");
    CloseableHttpResponse httpResponse = HTTP_CLIENT.execute(request);
    String result = IoUtil.read(httpResponse.getEntity().getContent()).toString();
    if(code != 200){
        throw new Exception("接口請求異常");
    }
 
    return result;
}

訪問接口地址:http://localhost:8080/retry_demo_httpclient?code=200。查看控制臺日志打?。?/p>

2.6、自定義重試工具

裝X的話,我們還可以自定義我們的重試工具。其實無非以下幾個步驟:

  • 自定義重試的工具類
  • 接收一個方法調(diào)用,并對該方法進行異常捕獲
  • 如果捕獲了該異常,則進行一定間隔,然后重新請求
  • 記錄請求次數(shù),如果超過上限,則提示異常信息

直接定義一個重試的工具類RetryUtil.java:

import cn.hutool.core.thread.ThreadUtil;
import lombok.extern.slf4j.Slf4j;
 
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.function.Supplier;
 
@Slf4j
public class RetryUtil {
 
 
    /**
     * 重試方法
     * @param invokeFunc   原方法調(diào)用
     * @param maxAttempts  重試次數(shù)上限
     * @param deplay   重試的間隔時間
     * @param timeUnit   重試的間隔時間單位
     * @param faultFunc   如果超過重試上限次數(shù),那么會執(zhí)行該錯誤回調(diào)方法
     * @return
     * @param <T>
     */
    public static <T> T retry(Supplier<T> invokeFunc, int maxAttempts, long deplay, TimeUnit timeUnit, Function<Throwable, T> faultFunc) {
        AtomicInteger retryTimes = new AtomicInteger(0);
        for(;;) {
            try{
                return invokeFunc.get();
            } catch (Throwable th) {
                if(retryTimes.get() > maxAttempts){
                    log.error("重試次數(shù)超過{}次,進入失敗回調(diào)", retryTimes.get());
                    return faultFunc.apply(th);
                }
                ThreadUtil.sleep(deplay, timeUnit);
                retryTimes.getAndAdd(1);
            }
        }
    }
 
}

工具類使用:

@GetMapping("retry_demo_custom")
public String retry_demo_custom(Integer code)  {
    return RetryUtil.retry(() -> {
        String result = null;
        try {
            result = customRetry(code);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return result;
    }, 3, 1000, TimeUnit.MILLISECONDS, Throwable::getMessage);
}
 
private String customRetry(int code) throws Exception {
    log.info("請求customRetry接口");
    String result = HttpUtil.get("http://localhost:8080/http_test");
    if(code != 200){
        throw new Exception("接口請求異常");
    }
 
    return result;
}

執(zhí)行完后,訪問地址:http://localhost:8080/retry_demo_custom?code=2001

這里只是簡單的進行了定義,如果項目中使用肯定需要考慮更復雜的因素。如進入重試時不一定只有異常的時候需要重試,可以指定重試策略,然后制定進入重試策略的規(guī)則。

2.7、并發(fā)框架異步重試

在 Java 并發(fā)框架中,異步重試通常涉及到使用線程池和定時器,以便在異步任務失敗后進行重試。以下是一個簡單的示例,演示了如何使用 CompletableFuture、ScheduledExecutorService 和 CompletableFuture.supplyAsync 來實現(xiàn)異步任務的重試。

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
 
public class AsyncRetryExample {
 
    private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
 
    public static void main(String[] args) {
        // 示例異步任務,這里使用 supplyAsync,你可以根據(jù)實際情況選擇其他異步任務
        CompletableFuture<String> asyncTask = CompletableFuture.supplyAsync(() -> performAsyncTask("Task"));
 
        // 異步任務失敗后的重試邏輯
        retryAsyncTask(asyncTask, 3, 1, TimeUnit.SECONDS);
    }
 
    private static CompletableFuture<String> performAsyncTask(String taskName) {
        // 模擬異步任務,這里可以是任何異步操作
        System.out.println("Performing async task: " + taskName);
        // 這里模擬任務失敗的情況
        throw new RuntimeException("Task failed");
    }
 
    private static <T> void retryAsyncTask(CompletableFuture<T> asyncTask, int maxRetries, long delay, TimeUnit timeUnit) {
        asyncTask.exceptionally(throwable -> {
            // 異步任務失敗后的處理邏輯
            System.out.println("Task failed: " + throwable.getMessage());
 
            // 重試邏輯
            if (maxRetries > 0) {
                System.out.println("Retrying...");
 
                CompletableFuture<T> retryTask = CompletableFuture.supplyAsync(() -> performAsyncTask("Retry Task"));
                // 遞歸調(diào)用,進行重試
                retryAsyncTask(retryTask, maxRetries - 1, delay, timeUnit);
            } else {
                System.out.println("Max retries reached. Task failed.");
            }
 
            return null; // 必須返回 null,否則會影響鏈式調(diào)用
        });
    }
}

示例中,performAsyncTask 模擬了一個異步任務,如果任務失敗,它會拋出一個運行時異常。retryAsyncTask 方法用于處理異步任務的失敗情況,并進行重試。在重試時,它使用 CompletableFuture.supplyAsync 創(chuàng)建一個新的異步任務,模擬了重試的過程。請注意,這只是一個簡單的示例,實際應用中可能需要更復雜的重試策略和錯誤處理邏輯。

2.8、消息隊列

網(wǎng)上還有一種消息隊列的方式來實現(xiàn),這里沒過多的去研究過,目前以上幾種方式應該也是夠用的了。這里直接貼出網(wǎng)上的部分代碼,使用 RabbitMQ 作為消息隊列,演示了請求重試的實現(xiàn):

首先添加依賴:

<dependencies>
    <dependency>
        <groupId>com.rabbitmq</groupId>
        <artifactId>amqp-client</artifactId>
        <version>5.13.1</version>
    </dependency>
</dependencies>

然后,創(chuàng)建一個發(fā)送者和接收者類:

消息發(fā)送者(Producer)

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
 
import java.io.IOException;
import java.util.concurrent.TimeoutException;
 
public class MessageProducer {
 
    private static final String QUEUE_NAME = "retry_queue";
 
    public static void main(String[] args) throws IOException, TimeoutException {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("localhost");
 
        try (Connection connection = factory.newConnection(); Channel channel = connection.createChannel()) {
            channel.queueDeclare(QUEUE_NAME, false, false, false, null);
 
            // 模擬發(fā)送請求
            String request = "Your request data";
 
            // 將請求發(fā)送到隊列
            channel.basicPublish("", QUEUE_NAME, null, request.getBytes());
            System.out.println(" [x] Sent '" + request + "'");
        }
    }
}

消息接收者(Consumer)

import com.rabbitmq.client.*;
 
import java.io.IOException;
import java.util.concurrent.TimeoutException;
 
public class MessageConsumer {
 
    private static final String QUEUE_NAME = "retry_queue";
 
    public static void main(String[] args) throws IOException, TimeoutException {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("localhost");
 
        try (Connection connection = factory.newConnection(); Channel channel = connection.createChannel()) {
            channel.queueDeclare(QUEUE_NAME, false, false, false, null);
 
            // 設置消息監(jiān)聽器
            DeliverCallback deliverCallback = (consumerTag, delivery) -> {
                String request = new String(delivery.getBody(), "UTF-8");
 
                // 模擬處理請求,這里可能會出現(xiàn)處理失敗的情況
                boolean processingSucceeded = processRequest(request);
 
                if (processingSucceeded) {
                    System.out.println(" [x] Received and processed: '" + request + "'");
                } else {
                    // 處理失敗,將請求重新放入隊列,進行重試
                    channel.basicPublish("", QUEUE_NAME, null, delivery.getBody());
                    System.out.println(" [x] Processing failed. Retrying: '" + request + "'");
                }
            };
 
            // 消費消息
            channel.basicConsume(QUEUE_NAME, true, deliverCallback, consumerTag -> {
            });
        }
    }
 
    private static boolean processRequest(String request) {
        // 模擬處理請求的方法
        // 在實際應用中,這里應該是對請求的處理邏輯
        // 返回 true 表示處理成功,返回 false 表示處理失敗,需要進行重試
        // 這里簡單地模擬了一個失敗的情況
        return !request.equals("Your request data");
    }
}

示例中,消息發(fā)送者(MessageProducer)將請求發(fā)送到名為 "retry_queue" 的隊列中。消息接收者(MessageConsumer)監(jiān)聽隊列,當接收到消息時,模擬處理請求的邏輯。如果處理失敗,將請求重新放入隊列進行重試。

3、小結(jié)

接口請求重試機制對保證系統(tǒng)高可用非常關鍵,需要根據(jù)業(yè)務需求選擇合適的重試策略。常用的組合策略包括帶最大次數(shù)的定時/指數(shù)退避重試、故障轉(zhuǎn)移重試等。重試機制需要綜合設置以達到容錯效果 又避免產(chǎn)生過大的系統(tǒng)負載。

以上就是Java中HTTP接口請求重試的實現(xiàn)方式的詳細內(nèi)容,更多關于Java HTTP接口請求重試的資料請關注腳本之家其它相關文章!

相關文章

  • 查看import的類是出自哪個jar包的方法

    查看import的類是出自哪個jar包的方法

    下面小編就為大家?guī)硪黄榭磇mport的類是出自哪個jar包的方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-03-03
  • MyBatisPlus 一對多、多對一、多對多的完美解決方案

    MyBatisPlus 一對多、多對一、多對多的完美解決方案

    這篇文章主要介紹了MyBatisPlus 一對多、多對一、多對多的完美解決方案,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-11-11
  • 基于Java在netty中實現(xiàn)線程和CPU綁定

    基于Java在netty中實現(xiàn)線程和CPU綁定

    這篇文章主要介紹了基于Java在netty中實現(xiàn)線程和CPU綁定,文章圍繞主題的相關內(nèi)容展開詳細介紹,具有一定的參考價值,需要的小伙伴可以參考一下
    2022-05-05
  • IDEA中解決 git pull 沖突的方法

    IDEA中解決 git pull 沖突的方法

    這篇文章主要介紹了IDEA中解決 git pull 沖突的方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-07-07
  • java與C 代碼運行效率的對比(整理)

    java與C 代碼運行效率的對比(整理)

    最近和朋友無意間討論起了 有關java 和C 的 效率問題, (我是java 推介者, 他是 c 語言推介者, 他做的是嵌入式)故,想通過網(wǎng)絡查詢一下, 總結(jié)一下,兩者到底效率如何,其有何差異,原因又是啥?各種優(yōu)勢有在何處?
    2021-04-04
  • 性能爆棚的實體轉(zhuǎn)換復制工具MapStruct使用詳解

    性能爆棚的實體轉(zhuǎn)換復制工具MapStruct使用詳解

    這篇文章主要為大家介紹了性能爆棚的實體轉(zhuǎn)換復制工具MapStruct使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-03-03
  • spring整合redis實現(xiàn)數(shù)據(jù)緩存的實例代碼

    spring整合redis實現(xiàn)數(shù)據(jù)緩存的實例代碼

    這篇文章主要介紹了spring整合redis實現(xiàn)數(shù)據(jù)緩存,需要的朋友可以參考下
    2018-09-09
  • 一文解析Java開發(fā)中高頻使用的網(wǎng)絡協(xié)議

    一文解析Java開發(fā)中高頻使用的網(wǎng)絡協(xié)議

    對于Java開發(fā)者而言,無需深入?yún)f(xié)議底層實現(xiàn),但必須掌握常用協(xié)議的核心原理,應用場景和Java代碼實操,才能高效開發(fā)網(wǎng)絡通信相關功能,下面我們就來重點解析一下Java開發(fā)中高頻使用的網(wǎng)絡協(xié)議吧
    2026-04-04
  • 深入理解java final不可變性

    深入理解java final不可變性

    本文主要介紹了講講java final不可變性,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • springboot接入微信app支付的方法

    springboot接入微信app支付的方法

    本文使用springboot集成微信支付服務,包含微信統(tǒng)一支付訂單接口,以及支付回調(diào)接口等,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-05-05

最新評論

巴里| 湘潭市| 皋兰县| 饶阳县| 伊金霍洛旗| 象山县| 遵化市| 灵宝市| 衡东县| 武穴市| 竹北市| 卢龙县| 板桥市| 大姚县| 城固县| 通渭县| 庆城县| 襄垣县| 八宿县| 祁东县| 牡丹江市| 兴文县| 滨海县| 长治市| 乌苏市| 类乌齐县| 永靖县| 扎囊县| 南汇区| 海淀区| 佛教| 小金县| 如皋市| 遵义县| 宁晋县| 桂东县| 图木舒克市| 佛学| 南充市| 米泉市| 天台县|