溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Spring@async方法如何添加注解實現(xiàn)異步調(diào)用

發(fā)布時間:2021-03-05 15:16:43 來源:億速云 閱讀:179 作者:小新 欄目:編程語言

小編給大家分享一下Spring@async方法如何添加注解實現(xiàn)異步調(diào)用,希望大家閱讀完這篇文章之后都有所收獲,下面讓我們一起去探討吧!

這篇文章主要介紹了Spring @async方法如何添加注解實現(xiàn)異步調(diào)用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下

在我們使用spring框架的過程中,在很多時候我們會使用@async注解來異步執(zhí)行某一些方法,提高系統(tǒng)的執(zhí)行效率。今天我們來探討下 spring 是如何完成這個功能的。

spring 在掃描bean的時候會掃描方法上是否包含@async的注解,如果包含的,spring會為這個bean動態(tài)的生成一個子類,我們稱之為代理類(?), 代理類是繼承我們所寫的bean的,然后把代理類注入進(jìn)來,那此時,在執(zhí)行此方法的時候,會到代理類中,代理類判斷了此方法需要異步執(zhí)行,就不會調(diào)用父類 (我們原本寫的bean)的對應(yīng)方法。spring自己維護(hù)了一個隊列,他會把需要執(zhí)行的方法,放入隊列中,等待線程池去讀取這個隊列,完成方法的執(zhí)行, 從而完成了異步的功能。

我們可以關(guān)注到再配置task的時候,是有參數(shù)讓我們配置線程池的數(shù)量的。因為這種實現(xiàn)方法,所以在同一個類中的方法調(diào)用,添加@async注解是失效的!,原因是當(dāng)你在同一個類中的時候,方法調(diào)用是在類體內(nèi)執(zhí)行的,spring無法截獲這個方法調(diào)用。

那在深入一步,spring為我們提供了AOP,面向切面的功能。他的原理和異步注解的原理是類似的,spring在啟動容器的時候,會掃描切面所定義的 類。在這些類被注入的時候,所注入的也是代理類,當(dāng)你調(diào)用這些方法的時候,本質(zhì)上是調(diào)用的代理類。通過代理類再去執(zhí)行父類相對應(yīng)的方法,那spring只 需要在調(diào)用之前和之后執(zhí)行某段代碼就完成了AOP的實現(xiàn)了!

那最后我們還有一個問題,spring是如何動態(tài)的生成某一個類的子類的?代理類?

簡單介紹:

Spring為任務(wù)調(diào)度與異步方法執(zhí)行提供了注解支持。通過在方法上設(shè)置@Async注解,可使得方法被異步調(diào)用。也就是說調(diào)用者會在調(diào)用時立即返回,而被調(diào)用方法的實際執(zhí)行是交給Spring的TaskExecutor來完成。

開啟@Async注解:

<task:annotation-driven executor="annotationExecutor" /><!-- 支持 @Async 注解 --><task:executor id="annotationExecutor" pool-size="20"/>

同時加入<context:component-scan />掃描注解。

為了比較,先來一個同步調(diào)用:

@Componentpublic class TestAsyncBean {  public void sayHello4() throws InterruptedException {    Thread.sleep(2 * 1000);//網(wǎng)絡(luò)連接中 。。。消息發(fā)送中。。。    System.out.println("我愛你啊!");}

@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration({"classpath:/applicationContext.xml"})public class TestAsync {  @Test  public void test_sayHello4() throws InterruptedException, ExecutionException {    System.out.println("你不愛我了么?");    testAsyncBean.sayHello4();    System.out.println("回的這么慢, 你肯定不愛我了, 我們還是分手吧。。。");    Thread.sleep(3 * 1000);// 不讓主進(jìn)程過早結(jié)束  }}

輸出結(jié)果:

你不愛我了么?我愛你啊!回的這么慢, 你肯定不愛我了, 我們還是分手吧。。。

同步調(diào)用會按代碼順序依次進(jìn)行下去,如果哪里需要等待,那么就阻塞在那里,不再向下繼續(xù)進(jìn)行。

使用@Async的異步調(diào)用:

@Componentpublic class TestAsyncBean {  @Async  public void sayHello3() throws InterruptedException {    Thread.sleep(2 * 1000);//網(wǎng)絡(luò)連接中 。。。消息發(fā)送中。。。    System.out.println("我愛你啊!");  }}

@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration({"classpath:/applicationContext.xml"})public class TestAsync {  @Autowired  private TestAsyncBean testAsyncBean;  @Test  public void test_sayHello3() throws InterruptedException, ExecutionException {    System.out.println("你不愛我了么?");    testAsyncBean.sayHello3();    System.out.println("你竟無話可說, 我們分手吧。。。");    Thread.sleep(3 * 1000);// 不讓主進(jìn)程過早結(jié)束  }}

輸出結(jié)果:

你不愛我了么?你竟無話可說, 我們分手吧。。。我愛你啊!

異步調(diào)用,通過開啟新的線程來執(zhí)行調(diào)用的方法,不影響主線程。異步方法實際的執(zhí)行交給了Spring的TaskExecutor來完成。

上面這種方式是沒有返回值的,下面嘗試有返回值的異步調(diào)用:

@Componentpublic class TestAsyncBean {  @Async  public String sayHello2() throws InterruptedException {    Thread.sleep(2 * 1000);//網(wǎng)絡(luò)連接中 。。。消息發(fā)送中。。。    return "我愛你啊!";// 調(diào)用方調(diào)用后會立即返回,所以返回null  }}

@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration({"classpath:/applicationContext.xml"})public class TestAsync {  @Autowired  private TestAsyncBean testAsyncBean;  @Test  public void test_sayHello2() throws InterruptedException, ExecutionException {    System.out.println("你不愛我了么?");    System.out.println(testAsyncBean.sayHello2());    System.out.println("你說的啥? 我們還是分手吧。。。");    Thread.sleep(3 * 1000);// 不讓主進(jìn)程過早結(jié)束  }}

輸出結(jié)果:

你不愛我了么?null你說的啥? 我們還是分手吧。。。

通過直接獲取返回值得方式是不行的,這里就需要用到異步回調(diào),異步方法返回值必須為Future<>,就像Callable與Future。

下面通過AsyncResult<>來獲得異步調(diào)用的返回值:

@Componentpublic class TestAsyncBean {  @Async  public Future<String> sayHello1() throws InterruptedException {    int thinking = 2;    Thread.sleep(thinking * 1000);//網(wǎng)絡(luò)連接中 。。。消息發(fā)送中。。。    System.out.println("我愛你啊!");    return new AsyncResult<String>("發(fā)送消息用了"+thinking+"秒");  }}

@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration({"classpath:/applicationContext.xml"})public class TestAsync {  @Autowired  private TestAsyncBean testAsyncBean;  @Test  public void test_sayHello1() throws InterruptedException, ExecutionException {    Future<String> future = null;    System.out.println("你不愛我了么?");    future = testAsyncBean.sayHello1();    System.out.println("你竟無話可說, 我們分手吧。。。");    Thread.sleep(3 * 1000);// 不讓主進(jìn)程過早結(jié)束    System.out.println(future.get());  }}

輸出結(jié)果:

你不愛我了么?你竟無話可說, 我們分手吧。。。我愛你啊!

發(fā)送消息用了2秒

看完了這篇文章,相信你對“Spring@async方法如何添加注解實現(xiàn)異步調(diào)用”有了一定的了解,如果想了解更多相關(guān)知識,歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI