驗證碼的非同步機制
上一篇講過可以用郵件發驗證碼,通常我們在某網站發驗證碼時,首先會提示驗證碼已發送,請檢查郵箱或者簡訊,這就是圖中的1和3。然而此時查看郵箱或簡訊可能並沒有收到驗證碼,往往要過幾秒種才真正收到,這就是圖中的2和4。2和4所消耗的時間比1和3要多,如果是同步,先執行4後執行3,那麼這個請求將一直佔用後台伺服器。如果是非同步,可以在第一時間通知使用者已發送,並釋放請求,而完全不用去管2和4的執行過程。如果2和4執行不成功怎麼辦。在驗證碼提示訊息結尾,我們經常可以看到:”如果你在XXX秒鐘之內沒有收到驗證碼,請重發“ @Async和@EnableAsync 實現非同步 控制層
[java] view plain copy @GetMapping("/async") public String test1() throws InterruptedException { helloService.task1(); helloService.task2(); System.out.println("釋放請求"); return "ok"; } 服務層 [java] view plain copy @Async public void task1() throws InterruptedException{ Thread.sleep(2000); System.out.println("完成任務1"); } @Async public void task2() throws InterruptedException{ Thread.sleep(1000); System.out.println("完成任務2"); } 這是在一個控制層中調用了兩個服務層的方法,任務1需要執行2秒時間,任務2需要執行1秒時間。和普通方法的唯一區別就是非同步方法呼叫上加了@Async
上圖是執行結果 ,這是同步。如果要讓@Async非同步生效還需要在配置類中開啟非同步,如下 [java] view plain copy @EnableAsync @SpringBootApplication 再次執行
執行順序和前面完全顛倒,在第一時間就釋放了請求,任務2和任務1是同時執行的,但是任務2時間短,所以比任務1先執行完。
應用情境 這個非同步實際上就是spring封裝了一個基本的多線程功能,每個@Async都會開啟一個新的線程,並且 在內部使用了線程池。非同步線程執行完後並沒有回調方法得知任務是否執行成功,在一般的web情境下,非同步回調是在前端用ajax的方式來實現的,一個頁面可以有多個ajax,每個ajax去獨立完成一個後台業務,誰先完成誰先響應,彼此互不干涉。後台業務則應該是彼此獨立的以供ajax調用,如果在後台回調意味著多個業務任務整合到一個請求,而且這個請求的回應時間要按最慢的那個任務計算。所以這種後台非同步只適用於對請求結果即時性要求不高的情境,不建議在後台使用回調。這也是我在第三篇Rest風格介面中講過的,使用靜態html+ajax,而不用動態jsp的原因之一。