1. 程式人生 > >springboot之非同步任務,有彩蛋!

springboot之非同步任務,有彩蛋!

springboot非同步任務

ps:文中有個小彩蛋玩笑,請勿當真

應用場景 :舉個栗子:一般在專案開發中都會有登入成功失敗記錄日誌,或者記錄操作日誌的需求,如果不採用非同步記錄的方式,多少會影響介面的效率,故採用非同步的方式記錄

  • springboot2.x中非同步的使用:
  • 非同步的方法均位於org.springframework.scheduling.annotation

1.建立springboot專案
2.在啟動類添加註解@EnableAsync

@SpringBootApplication
@ServletComponentScan
@EnableWebSocket
@EnableScheduling @EnableAsync //開啟非同步任務 public class GunsApplication { public static void main(String[] args) { System.setProperty("es.set.netty.runtime.available.processors", "false"); SpringApplication.run(GunsApplication.class, args); } }

2.編寫需要非同步處理的業務

// 模擬非同步業務
@Component
public class AnyscTask { public static Random random =new Random(); @Async public void doTaskOne() throws Exception { System.out.println("開始任務一:記錄登入日誌"); long start = System.currentTimeMillis(); Thread.sleep(random.nextInt(10000)); long end = System.currentTimeMillis
(); System.out.println("完成任務一,耗時:" + (end - start) + "毫秒"); } @Async public void doTaskTwo() throws Exception { System.out.println("開始任務二:記錄操作日誌"); long start = System.currentTimeMillis(); Thread.sleep(random.nextInt(10000)); long end = System.currentTimeMillis(); System.out.println("完成任務二,耗時:" + (end - start) + "毫秒"); } @Async public void doTaskThree() throws Exception { System.out.println("開始任務三:暴打產品經理"); long start = System.currentTimeMillis(); Thread.sleep(random.nextInt(10000)); long end = System.currentTimeMillis(); System.out.println("完成任務三,耗時:" + (end - start) + "毫秒"); } }
  • 可以看到在需要非同步執行的方法加上 註解@Async 該方法就會變成非同步方法,是不是很簡單:)

  • 測試類測試

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Slf4j
public class MessageQueue {
   @Autowired
   private AnyscTask anysc;
   @Test
   public void aysncTest(){
       try {
           System.out.println("模擬操作:假裝自己登陸失敗啦");
           this.anysc.doTaskOne();
           this.anysc.doTaskTwo();
           this.anysc.doTaskThree();
           System.out.println("模擬返回給使用者message:你登入失敗啦");
       } catch (Exception e) {
           e.printStackTrace();
       }
   }
}
  • 執行以上程式碼後console列印為:
模擬操作:假裝自己登陸失敗啦
模擬返回給使用者message:你登入失敗啦
開始任務三:暴打產品經理
開始任務二:記錄操作日誌
開始任務一:記錄登入日誌
  • 第二次執行
模擬操作:假裝自己登陸失敗啦
模擬返回給使用者message:你登入失敗啦
開始任務一:記錄登入日誌
開始任務二:記錄操作日誌
開始任務三:暴打產品經理
  • 通過上面的測試我們可以發現模擬介面會先返回給使用者登入失敗的狀態,再去記錄登入失敗等一系列操作,這樣使用者就會第一時間知道自己操作失敗,體驗提升大大的

**注意**:

1.本人在第一次測試時,直接將非同步執行的方法和測試類寫到一起,發現並沒有按照預期的執行結果列印.簡單來說,因為Spring在啟動掃描時會為其建立一個代理類,而同類呼叫時,還是呼叫本身的代理類的,所以和平常呼叫是一樣的。其他的註解如@Cache等也是一樣的道理,說白了,就是Spring的代理機制造成的。

2.還有個問題不知道大家看到沒有,非同步方法中執行完之後的輸出沒有列印

System.out.println("完成任務一,耗時:" + (end - start) + "毫秒");
System.out.println("完成任務二,耗時:" + (end - start) + "毫秒");
System.out.println("完成任務三,耗時:" + (end - start) + "毫秒");

這是因為這三個非同步任務,同時開始執行,而非同步不在spring的生命週期範圍之內,所以測試類預設當前例項已經銷燬,故不會再進行列印,如果需要操作帶有返回值的非同步任務,需要使用Futrue(回撥函式)進行封裝

  • 下個文章我會記錄一下Futrue回撥函式的使用,還有在Springboot中如何優化非同步任務池等
  • 第一次寫文章,寫的不好的地方請多包涵! 希望和你們一起進步,加油,我(你)是最胖的!!!
  • 如果有閱讀量的話後續本人還有持續更新一些SpringBoot,SpringCloud,Redis,Elasticsearch-JavaApi,等一些java後端技術乾貨,如果喜歡的話可以點個關注,雙擊666!!!(開玩笑的哈哈)