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

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

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

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

一、背景

對(duì)于一個(gè)頁(yè)面上的所有實(shí)例有一個(gè)查詢(xún)權(quán)限的接口,同時(shí)有四個(gè)操作類(lèi)型的需要查詢(xún)且接口僅支持單個(gè)實(shí)例單個(gè)操作類(lèi)型操作。

簡(jiǎn)單來(lái)說(shuō),假設(shè)實(shí)例查詢(xún)退訂權(quán)限需要1秒鐘,那么四個(gè)操作共需4秒鐘,一共20個(gè)實(shí)例的話(huà),那么實(shí)際所需時(shí)間為80秒。

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

二、設(shè)計(jì)方案

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

(一)使用框架

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

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

由于Feign的特殊性,目前并不支持異步返回Future,直接通過(guò)Future是會(huì)報(bào)錯(cuò)的。

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

三、示例代碼

項(xiàng)目代碼我就不放上來(lái)了,我將寫(xiě)一個(gè)Demo作為示例,基本的思想都在里面了。

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

1. 配置異步化及異步線(xiàn)程池 - AsyncConfig類(lèi)

@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;
 
    /**
     * 異步測(cè)試方法
     * @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í)行四個(gè)用戶(hù)的查詢(xún)操作
        futures.add(asyncService.testFuture(ids[1]));
        futures.add(asyncService.testFuture(ids[2]));
        futures.add(asyncService.testFuture(ids[3]));
        return asyncService.getReturnValueMange(futures); 異步方法 異步獲取所有的異步回調(diào)值
    }
 
    /**
     * 同步測(cè)試方法
     * @param i
     * @return
     * @throws InterruptedException
     */
    @GetMapping("/syncTest")
    public User testsyncTest( Integer i) throws InterruptedException {
        User user = asyncService.testSync(i);
        return user;
    }
}

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

3. AsyncService層

@Slf4j
@Service
public class AsyncService {
 
    @Autowired
    private AsyncUnit asyncUnit; //異步實(shí)現(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;
    }
 
    //獲取異步方法結(jié)果
    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 {
 
    //異步方法,通過(guò)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;
 
    //異步測(cè)試方法,查詢(xún)五次 模擬所需時(shí)間
    @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;
    }
 
    //同步測(cè)試方法,通過(guò)執(zhí)行5次同步方法模擬查詢(xún)
    @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)用方的服務(wù)名為ASYNC,通過(guò)Feign調(diào)用,F(xiàn)eign的詳細(xì)說(shuō)明就不細(xì)說(shuō),具體可以自行查詢(xún)。

(三)公共類(lèi) 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;
    }
 
}

四、實(shí)現(xiàn)效果測(cè)試

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

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

控制臺(tái)日志

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

控制臺(tái)日志

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

五、總結(jié)

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

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

相關(guān)文章

  • JDK的命令詳解

    JDK的命令詳解

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

    idea2020安裝MybatisCodeHelper插件的圖文教程

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

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

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

    SpringBoot操作Jedis案例代碼

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

    spark中使用groupByKey進(jìn)行分組排序的示例代碼

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

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

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

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

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

    零基礎(chǔ)搭建boot+MybatisPlus的詳細(xì)教程

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

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

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

    Hbase、elasticsearch整合中jar包沖突的問(wèn)題解決

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

最新評(píng)論

仪陇县| 屏山县| 伽师县| 滦南县| 洱源县| 苗栗县| 古田县| 麻栗坡县| 永修县| 佛坪县| 荃湾区| 遂川县| 冕宁县| 扎囊县| 通海县| 台南市| 聂荣县| 甘泉县| 普兰县| 尼木县| 中方县| 宝山区| 连云港市| 兖州市| 绵阳市| 长沙县| 南平市| 镇沅| 河津市| 新田县| 通州区| 岫岩| 金塔县| 马尔康县| 舟曲县| 兴义市| 睢宁县| 金川县| 林甸县| 浦县| 府谷县|