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

Spring?異步接口返回結(jié)果的四種方式

 更新時間:2022年08月28日 16:52:27   作者:魚找水需要時間  
這篇文章主要介紹了Spring?異步接口返回結(jié)果的四種方式,文章圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考價值,感興趣的小伙伴可以參考一下

1. 需求

開發(fā)中我們經(jīng)常遇到異步接口需要執(zhí)行一些耗時的操作,并且接口要有返回結(jié)果。

使用場景:用戶綁定郵箱、手機號,將郵箱、手機號保存入庫后發(fā)送郵件或短信通知
接口要求:數(shù)據(jù)入庫后給前臺返回成功通知,后臺異步執(zhí)行發(fā)郵件、短信通知操作

一般的話在企業(yè)中會借用消息隊列來實現(xiàn)發(fā)送,業(yè)務(wù)量大的話有一個統(tǒng)一消費、管理的地方。但有時項目中沒有引用mq相關(guān)組件,這時為了實現(xiàn)一個功能去引用、維護一個消息組件有點大材小用,下面介紹幾種不引用消息隊列情況下的解決方式

定義線程池:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.ThreadPoolExecutor;
/**
 * @description: 公共配置
 * @author: yh
 * @date: 2022/8/26
 */
@EnableAsync
@Configuration
public class CommonConfig {
    @Bean
    public TaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

        // 設(shè)置核心線程數(shù)
        executor.setCorePoolSize(50);
        // 設(shè)置最大線程數(shù)
        executor.setMaxPoolSize(200);
        // 設(shè)置隊列容量
        executor.setQueueCapacity(200);
        // 設(shè)置線程活躍時間(秒)
        executor.setKeepAliveSeconds(800);
        // 設(shè)置默認線程名稱
        executor.setThreadNamePrefix("task-");
        // 設(shè)置拒絕策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 等待所有任務(wù)結(jié)束后再關(guān)閉線程池
        executor.setWaitForTasksToCompleteOnShutdown(true);
        return executor;
    }
}

2. 解決方案

2.1 @Async

定義異步任務(wù),如發(fā)送郵件、短信等

@Service
public class ExampleServiceImpl implements ExampleService {
    @Async("taskExecutor")
    @Override
    public void sendMail(String email) {
        try {
            Thread.sleep(3000);
            System.out.println("異步任務(wù)執(zhí)行完成, " + email + " 當(dāng)前線程:" + Thread.currentThread().getName());
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

Controller

@RequestMapping(value = "/api")
@RestController
public class ExampleController {
    @Resource
    private ExampleService exampleService;

    @RequestMapping(value = "/bind",method = RequestMethod.GET)
    public String bind(@RequestParam("email") String email) {
        long startTime = System.currentTimeMillis();
        try {
            // 綁定郵箱....業(yè)務(wù)
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        //模擬異步任務(wù)(發(fā)郵件通知、短信等)
        exampleService.sendMail(email);

        long endTime = System.currentTimeMillis();
        System.out.println("方法執(zhí)行完成返回,耗時:" + (endTime - startTime));
        return "ok";
    }
}

運行結(jié)果:

2.2 TaskExecutor

@RequestMapping(value = "/api")
@RestController
public class ExampleController {
    @Resource
    private ExampleService exampleService;
    @Resource
    private TaskExecutor taskExecutor;

    @RequestMapping(value = "/bind", method = RequestMethod.GET)
    public String bind(@RequestParam("email") String email) {
        long startTime = System.currentTimeMillis();
        try {
            // 綁定郵箱....業(yè)務(wù)
            Thread.sleep(2000);

            // 將發(fā)送郵件交給線程池去執(zhí)行
            taskExecutor.execute(() -> {
                exampleService.sendMail(email);
            });
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        long endTime = System.currentTimeMillis();
        System.out.println("方法執(zhí)行完成返回,耗時:" + (endTime - startTime));
        return "ok";
    }
}

運行結(jié)果:

2.3 Future

首先去掉Service方法中的@Async("taskExecutor"),此時執(zhí)行就會變成同步,總計需要5s才能完成接口返回。這次我們使用jdk1.8中的CompletableFuture來實現(xiàn)異步任務(wù)

@RequestMapping(value = "/api")
@RestController
public class ExampleController {
    @Resource
    private ExampleService exampleService;
    @Resource
    private TaskExecutor taskExecutor;

    @RequestMapping(value = "/bind", method = RequestMethod.GET)
    public String bind(@RequestParam("email") String email) {
        long startTime = System.currentTimeMillis();
        try {
            // 綁定郵箱....業(yè)務(wù)
            Thread.sleep(2000);

            // 將發(fā)送郵件交給異步任務(wù)Future,需要記錄返回值用supplyAsync
            CompletableFuture.runAsync(() -> {
                exampleService.sendMail(email);
            }, taskExecutor);

        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        long endTime = System.currentTimeMillis();
        System.out.println("方法執(zhí)行完成返回,耗時:" + (endTime - startTime));
        return "ok";
    }
}

運行結(jié)果:

2.4 @EventListener

Spring為我們提供的一個事件監(jiān)聽、訂閱的實現(xiàn),內(nèi)部實現(xiàn)原理是觀察者設(shè)計模式;為的就是業(yè)務(wù)系統(tǒng)邏輯的解耦,提高可擴展性以及可維護性。事件發(fā)布者并不需要考慮誰去監(jiān)聽,監(jiān)聽具體的實現(xiàn)內(nèi)容是什么,發(fā)布者的工作只是為了發(fā)布事件而已。

2.4.1 定義event事件模型

public class NoticeEvent extends ApplicationEvent {
    private String email;
    private String phone;
    public NoticeEvent(Object source, String email, String phone) {
        super(source);
        this.email = email;
        this.phone = phone;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    public String getPhone() {
        return phone;
    }
    public void setPhone(String phone) {
        this.phone = phone;
    }
}

2.4.2 事件監(jiān)聽

@Component
public class ComplaintEventListener {

    /**
     * 只監(jiān)聽NoticeEvent事件
     * @author: yh
     * @date: 2022/8/27
     */
    @Async
    @EventListener(value = NoticeEvent.class)
//    @Order(1) 指定事件執(zhí)行順序
    public void sendEmail(NoticeEvent noticeEvent) {
        //發(fā)郵件
        try {
            Thread.sleep(3000);
            System.out.println("發(fā)送郵件任務(wù)執(zhí)行完成, " + noticeEvent.getEmail() + " 當(dāng)前線程:" + Thread.currentThread().getName());
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    @Async
    @EventListener(value = NoticeEvent.class)
//    @Order(2) 指定事件執(zhí)行順序
    public void sendMsg(NoticeEvent noticeEvent) {
        //發(fā)短信
        try {
            Thread.sleep(3000);
            System.out.println("發(fā)送短信步任務(wù)執(zhí)行完成, " + noticeEvent.getPhone() + " 當(dāng)前線程:" + Thread.currentThread().getName());
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

2.4.5 事件發(fā)布

@RequestMapping(value = "/api")
@RestController
public class ExampleController {
    /**
     * 用于事件推送
     * @author:  yh
     * @date:  2022/8/27
     */
    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

    @RequestMapping(value = "/bind", method = RequestMethod.GET)
    public String bind(@RequestParam("email") String email) {
        long startTime = System.currentTimeMillis();
        try {
            // 綁定郵箱....業(yè)務(wù)
            Thread.sleep(2000);

            // 發(fā)布事件,這里偷個懶手機號寫死
            applicationEventPublisher.publishEvent(new NoticeEvent(this, email, "13211112222"));
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("方法執(zhí)行完成返回,耗時:" + (endTime - startTime));
        return "ok";
    }
}

運行結(jié)果:

3. 總結(jié)

通過@Async、子線程、Future異步任務(wù)、Spring自帶ApplicationEvent事件監(jiān)聽都可以完成以上描述的需求。

到此這篇關(guān)于Spring 異步接口返回結(jié)果的四種方式的文章就介紹到這了,更多相關(guān)Spring 異步接口內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot之自定義banner使用代碼實例

    SpringBoot之自定義banner使用代碼實例

    這篇文章主要介紹了SpringBoot之自定義banner使用代碼實例,在Spring Boot中,你可以通過定制Banner來個性化你的應(yīng)用程序啟動時的輸出,Banner是一個在應(yīng)用程序啟動時顯示的ASCII藝術(shù)字形式的標志,用于增加應(yīng)用程序的識別度和個性化,需要的朋友可以參考下
    2024-01-01
  • Java界面編程實現(xiàn)界面跳轉(zhuǎn)

    Java界面編程實現(xiàn)界面跳轉(zhuǎn)

    這篇文章主要為大家詳細介紹了Java界面編程實現(xiàn)界面跳轉(zhuǎn),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • java圖形界面編程實戰(zhàn)代碼

    java圖形界面編程實戰(zhàn)代碼

    這篇文章主要介紹了java圖形界面編程實戰(zhàn)代碼,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-07-07
  • Spring?Boot?打包成Jar包運行原理分析

    Spring?Boot?打包成Jar包運行原理分析

    這篇文章主要為大家介紹了Spring?Boot?打包成Jar包運行的原理分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-09-09
  • Java中的java.lang.reflect.Type簡介

    Java中的java.lang.reflect.Type簡介

    在 Java 中,java.lang.reflect.Type 是一個接口,代表所有類型的通用超類型,它包括原始類型、參數(shù)化類型、數(shù)組類型、類型變量和基本類型,本文給大家講解Java中的java.lang.reflect.Type是什么,需要的朋友可以參考下
    2024-06-06
  • Java開發(fā)中的OOM內(nèi)存溢出問題詳解

    Java開發(fā)中的OOM內(nèi)存溢出問題詳解

    這篇文章主要介紹了Java開發(fā)中的OOM內(nèi)存溢出問題詳解,OOM,全稱?Out?Of?Memory,意思是內(nèi)存耗盡或內(nèi)存溢出,當(dāng)JVM因為沒有足夠的內(nèi)存來為對象分配空間并且垃圾回收器也已經(jīng)沒有空間可回收時,就會拋出這個?error,需要的朋友可以參考下
    2023-08-08
  • Java代碼是如何被CPU狂飆起來的

    Java代碼是如何被CPU狂飆起來的

    無論是剛剛?cè)腴TJava的新手還是已經(jīng)工作了的老司機,恐怕都不容易把Java代碼如何一步步被CPU執(zhí)行起來這個問題完全講清楚。本文就帶你詳細了解Java代碼到底是怎么運行起來的。感興趣的同學(xué)可以參考閱讀
    2023-03-03
  • 基于spring security實現(xiàn)登錄注銷功能過程解析

    基于spring security實現(xiàn)登錄注銷功能過程解析

    這篇文章主要介紹了基于spring security實現(xiàn)登錄注銷功能過程解析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-01-01
  • Java?SE循環(huán)一些基本練習(xí)題總結(jié)

    Java?SE循環(huán)一些基本練習(xí)題總結(jié)

    循環(huán)語句可以在滿足循環(huán)條件的情況下,反復(fù)執(zhí)行某一段代碼,這段被重復(fù)執(zhí)行的代碼被稱為循環(huán)體語句,下面這篇文章主要給大家總結(jié)介紹了關(guān)于Java?SE循環(huán)一些基本練習(xí)題,需要的朋友可以參考下
    2024-03-03
  • Java正則表達式的實例操作指南

    Java正則表達式的實例操作指南

    這篇文章主要給大家介紹了關(guān)于Java正則表達式的實例操作指南,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09

最新評論

定兴县| 循化| 长丰县| 华阴市| 台山市| 明溪县| 吉林市| 冷水江市| 和田县| 噶尔县| 郸城县| 鲜城| 桑日县| 高台县| 洮南市| 准格尔旗| 龙陵县| 德惠市| 子洲县| 沂水县| 义乌市| 南木林县| 治多县| 南皮县| 汉中市| 余江县| 广东省| 和硕县| 古蔺县| 珠海市| 普格县| 西和县| 舟曲县| 盐津县| 陕西省| 启东市| 瓦房店市| 治多县| 商水县| 芒康县| 田阳县|