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

SpringCloud解決Feign異步回調(diào)問題(SpringBoot+Async+Future實現(xiàn))

 更新時間:2022年11月23日 11:17:03   作者:弱水提滄  
這篇文章主要介紹了SpringCloud解決Feign異步回調(diào)問題(SpringBoot+Async+Future實現(xiàn)),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

近期,需要對之前的接口進行優(yōu)化,縮短接口的響應時間,但是springcloud中的feign是不支持傳遞異步化的回調(diào)結果的,因此有了以下的解決方案,記錄一下,僅供參考。

一、背景

對于一個頁面上的所有實例有一個查詢權限的接口,同時有四個操作類型的需要查詢且接口僅支持單個實例單個操作類型操作。

簡單來說,假設實例查詢退訂權限需要1秒鐘,那么四個操作共需4秒鐘,一共20個實例的話,那么實際所需時間為80秒。

這樣顯然是不符合要求的。經(jīng)過本文的優(yōu)化后,可以達到20秒。

二、設計方案

需要指出,由于各種限制原因,無法直接在工程中進行rest接口的調(diào)用,否則是直接可以@Async異步調(diào)用的。 

(一)使用框架

產(chǎn)品工程使用SpringCloud微服務,同時通過Feign調(diào)用權限的微服務,服務都是使用SpringBoot實現(xiàn)。

(二)實現(xiàn)方案

由于Feign的特殊性,目前并不支持異步返回Future,直接通過Future是會報錯的。

因此可以在權限微服務中異步執(zhí)行查詢操作權限,同時再異步起一個線程去等待所有的異步結果,這一個線程是阻塞的,同時由阻塞得到的最終結果,封裝成自己想要的返回體,返回給調(diào)用方即可,這樣相當于大致只需要等待一個實例的操作時間即可。

三、示例代碼

項目代碼我就不放上來了,我將寫一個Demo作為示例,基本的思想都在里面了。

(一)被調(diào)用方

1. 配置異步化及異步線程池 - AsyncConfig類

@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {
 
    @Bean("taskPoolExecutor")
    public Executor taskPoolExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(20);
        executor.setMaxPoolSize(30);
        executor.setQueueCapacity(200);
        executor.setKeepAliveSeconds(60);
        executor.setThreadNamePrefix("taskPoolExecutor-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return executor;
    }
 
    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new SimpleAsyncUncaughtExceptionHandler();
    }
}

2. Controller層 

@RestController
@Slf4j
public class AsyncController {
 
    @Autowired
    private AsyncService asyncService;
 
    /**
     * 異步測試方法
     * @param ids
     * @return
     * @throws Exception
     */
    @GetMapping("/future")
    public List<User> testFuture(int[] ids) throws Exception {
        List<Future<User>> futures = new ArrayList<>();
        futures.add(asyncService.testFuture(ids[0])); //異步方法 異步執(zhí)行四個用戶的查詢操作
        futures.add(asyncService.testFuture(ids[1]));
        futures.add(asyncService.testFuture(ids[2]));
        futures.add(asyncService.testFuture(ids[3]));
        return asyncService.getReturnValueMange(futures); 異步方法 異步獲取所有的異步回調(diào)值
    }
 
    /**
     * 同步測試方法
     * @param i
     * @return
     * @throws InterruptedException
     */
    @GetMapping("/syncTest")
    public User testsyncTest( Integer i) throws InterruptedException {
        User user = asyncService.testSync(i);
        return user;
    }
}

這里需要解釋說明下,使用一個list作為future結果的集合,同時采用getReturnValueMange(future)方法來獲取所有的異步執(zhí)行結果,具體可以看下面Service層的代碼邏輯。

3. AsyncService層

@Slf4j
@Service
public class AsyncService {
 
    @Autowired
    private AsyncUnit asyncUnit; //異步實現(xiàn)util
 
    public Future<User> testFuture(int i) throws InterruptedException {
        log.info("start...");
        long currentTime = System.currentTimeMillis();
        Future<User> user = asyncUnit.testUser(i);
        log.info("done...{}", String.valueOf(System.currentTimeMillis()- currentTime));
        return user;
    }
 
    //獲取異步方法結果
    public List<User> getReturnValueMange(List<Future<User>> futures) throws Exception {
        Future<List<User>> userFuture = asyncUnit.getReturnValueMange(futures);
        return userFuture.get(); //get()方法為阻塞方法,等待異步返回值
    }
 
    //同步方法-作為比較方法
    public User testSync(int i) throws InterruptedException {
        log.info("start...");
        Thread.sleep(2000);
        return new User(i);
    }

4. AsyncUtil 層

@Service
@Slf4j
public class AsyncUnit {
 
    //異步方法,通過sleep 2秒鐘模擬
    @Async("taskPoolExecutor")
    public Future<User> testUser(int age){
        log.info("異步執(zhí)行start...{}",Thread.currentThread().getName());
        long currentTime = System.currentTimeMillis();
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("異步執(zhí)行done...{}, {}",Thread.currentThread().getName(), String.valueOf(System.currentTimeMillis()- currentTime));
        return new AsyncResult<>(new User(age));
    }
 
    @Async("taskPoolExecutor")
    public Future<List<User>> getReturnValueMange(List<Future<User>> futures) throws Exception{
        log.info("異步執(zhí)行start..getReturnValueMange.{}",Thread.currentThread().getName());
        long currentTime = System.currentTimeMillis();
        List<User> users = new ArrayList<>();
        for (Future<User> future : futures) {
            users.add(future.get());
        }
        log.info(""+users.size());
        log.info("異步執(zhí)行done..getReturnValueMange.{}, {}",Thread.currentThread().getName(), String.valueOf(System.currentTimeMillis()- currentTime));
        return new AsyncResult<>(users);
    }
}

(二)調(diào)用方

1. Config 層

@Configuration
public class FeignConfig {
 
    @Bean
    public RequestInterceptor requestInterceptor() {
        return new FeignRequestInterceptor();
    }
}

2.  Controller層

@RestController
@Slf4j
public class AsyncController {
 
    @Autowired
    private RemoteClient remoteClient;
 
    //異步測試方法,查詢五次 模擬所需時間
    @GetMapping("/future")
    public List<Integer> testFuture() throws InterruptedException, ExecutionException {
        String res = "";
        log.info(" asynccontroller...start...");
        long currentTime = System.currentTimeMillis();
        int[] ids = new int[]{1,2,3,4,5};
        List<User> users = remoteClient.testFuture(ids);
        List<Integer> resList = new ArrayList<>();
        resList.add(users.get(1).getAge());
        log.info(" asynccontroller...done...{}", String.valueOf(System.currentTimeMillis()- currentTime));
        return  resList;
    }
 
    //同步測試方法,通過執(zhí)行5次同步方法模擬查詢
    @GetMapping("/syncTest")
    public String testsyncTest() {
        long currentTime = System.currentTimeMillis();
        List<Integer> ages = new ArrayList<>();
        for(int i=0; i<5; i++){
            User user = remoteClient.testsyncTest(i);
            ages.add(user.getAge());
        }
        log.info("done...{}", String.valueOf(System.currentTimeMillis()- currentTime));
        return  ages.get(0)+ages.get(1)+ages.get(2)+ages.get(3)+ages.get(4)+"";
    }
}

3. FeignClient (RemoteClient)層

@FeignClient(name = "ASYNC")
public interface RemoteClient {
 
 
    @GetMapping("/future")
    List<User> testFuture(@RequestParam("ids") int[] ids);
 
 
    @GetMapping("/futureValue")
    List<String> getReturnValueMange(@RequestBody List<Future<User>> futures);
 
    @GetMapping("/syncTest")
    User testsyncTest(@RequestParam("i") Integer i);
 
}

被調(diào)用方的服務名為ASYNC,通過Feign調(diào)用,F(xiàn)eign的詳細說明就不細說,具體可以自行查詢。

(三)公共類 User

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
 
    private String name;
    private String id;
    private int age;
    private String school;
 
    public User (int age){
        this.age = age;
    }
 
}

四、實現(xiàn)效果測試

調(diào)用方端口8305 被調(diào)用方8036 eureka端口 8761,將服務啟動如圖所示。

1. 使用Postman進行接口測試,首先是同步方法的執(zhí)行。

控制臺日志

2. 使用Postman進行異步方法調(diào)用

控制臺日志

 可以看到異步執(zhí)行之后,查詢結果由10秒縮短到2秒,這個優(yōu)化的時間為實例的個數(shù)為倍數(shù)作為縮短。

五、總結

本文的優(yōu)化方法基于Feign無法異步返回調(diào)用值得情況下采取的折中方法,如果遇到不在意返回值的異步返回可以直接進行異步執(zhí)行,這樣的話可以在毫秒級就執(zhí)行結束。

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

  • JDK的命令詳解

    JDK的命令詳解

    JDK的命令詳解...
    2006-12-12
  • idea2020安裝MybatisCodeHelper插件的圖文教程

    idea2020安裝MybatisCodeHelper插件的圖文教程

    這篇文章主要介紹了idea2020安裝MybatisCodeHelper插件的方法,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-09-09
  • Java面向?qū)ο缶幊讨衒inal關鍵字的使用方法詳解

    Java面向?qū)ο缶幊讨衒inal關鍵字的使用方法詳解

    這篇文章主要介紹了Java面向?qū)ο缶幊讨衒inal關鍵字的使用方法詳解,包括對內(nèi)部匿名類無法訪問外面的非 final 的變量問題的解讀,需要的朋友可以參考下
    2016-06-06
  • SpringBoot操作Jedis案例代碼

    SpringBoot操作Jedis案例代碼

    這篇文章主要介紹了SpringBoot操作Jedis案例代碼,代碼部分包括pom依賴、配置相關參數(shù)、JedisPool的設置,代碼簡單易懂對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-08-08
  • spark中使用groupByKey進行分組排序的示例代碼

    spark中使用groupByKey進行分組排序的示例代碼

    這篇文章主要介紹了spark中使用groupByKey進行分組排序的實例代碼,本文通過實例代碼給大家講解的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-03-03
  • Java堆內(nèi)存又溢出了!教你一招必殺技(推薦)

    Java堆內(nèi)存又溢出了!教你一招必殺技(推薦)

    這篇文章主要介紹了Java內(nèi)存溢出問題,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-04-04
  • Java虛擬機內(nèi)存溢出與內(nèi)存泄漏

    Java虛擬機內(nèi)存溢出與內(nèi)存泄漏

    這篇文章主要介紹了Java虛擬機內(nèi)存溢出與內(nèi)存泄漏,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-04-04
  • 零基礎搭建boot+MybatisPlus的詳細教程

    零基礎搭建boot+MybatisPlus的詳細教程

    這篇文章主要介紹了零基礎搭建boot+MybatisPlus,首先需要創(chuàng)建數(shù)據(jù)庫表和創(chuàng)建boot項目使用mybatisplus操作數(shù)據(jù)庫,本文通過示例代碼給大家介紹的非常詳細,需要的朋友可以參考下
    2022-03-03
  • springboot mybatis-plus實現(xiàn)登錄接口

    springboot mybatis-plus實現(xiàn)登錄接口

    本文主要介紹了springboot mybatis-plus實現(xiàn)登錄接口,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-11-11
  • Hbase、elasticsearch整合中jar包沖突的問題解決

    Hbase、elasticsearch整合中jar包沖突的問題解決

    本篇文章主要介紹了Hbase、elasticsearch整合中jar包沖突的問題解決,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-12-12

最新評論

双柏县| 陇川县| 喀喇沁旗| 大埔县| 玛纳斯县| 萍乡市| 庄浪县| 呼伦贝尔市| 察隅县| 玉龙| 乌拉特后旗| 扶绥县| 墨江| 手机| 莱州市| 监利县| 永吉县| 汾阳市| 海原县| 横峰县| 昌图县| 花莲县| 定日县| 涟源市| 禹城市| 长子县| 古浪县| 昌邑市| 九龙城区| 宁乡县| 怀集县| 和田县| 闵行区| 象州县| 汽车| 诸暨市| 肥东县| 重庆市| 满洲里市| 山东省| 临武县|