背景:前幾周,公司的一個項目須要發送郵件,起初並無考慮時間的影響,就未採用同步的方式進行發送。到了測試環境,發現須要發送郵件的地方耗時太久,所以研究了一下spring的異步方法支持—@Async,發現效果不錯,在這裏分享下。java
使用場景: 用於保證任務的及時性 ,適用於某一段耗時過長的代碼,例如發送短信、郵件、調用第三方接口等等... spring
1、開啓異步支持異步
<!-- 異步任務線程池 -->async
<task:annotation-driven executor="asyncExecutor"/>
<task:executor id="asyncExecutor" pool-size="5-20" queue-capacity="5"/>測試
注意: @Async、@Transactional等註解採用的是代理模式,若是在同一個類的某個方法上,調用本類帶有@Async等註解的方法是,該註解會失效。spa
2、 @Async用法線程
1. 註解應用範圍:代理
類: 若是該註解應用在類上,表示該類全部方法是異步的code
方法: 若是該註解應用在方法上,表示該方法是異步的blog
2. 基於無返回值的調用
public void resetPassword() { System.out.println("#resetPassword() - reset password start..."); smsHandler.send1(); System.out.println("#resetPassword() - reset password end..."); } @Async("asyncExecutor") public void send1() { Thread.sleep(5000); System.out.println("#notice1() - notice end..."); }
3. 基於@Async帶返回值的調用
public void resetPassword() { Future<String> future = smsHandler.send2(); System.out.println(future.isDone()); } @Async("asyncExecutor") public Future<String> send2() { Thread.sleep(5000); return new AsyncResult<String>("send success"); }
3、 @Async的異常處理
若是是基於有返回值的調用,可經過Futrue進行異常的封裝。若是是無返回值得調用,異常將沒法被捕獲和傳遞。Spring提供了AsyncUncaughtExceptionHandler接口進行該類問題的處理,默認的實現是 org.springframework.aop.interceptor.SimpleAsyncUncaughtExceptionHandler, 咱們能夠也能夠實現AsyncUncaughtExceptionHandler,實現本身項目須要的異常處理。
1. 自定義異常處理類
@Component("unbenAsyncUncaughtExceptionHandler") public class UnbenAsyncUncaughtExceptionHandler implements AsyncUncaughtExceptionHandler { private static final Logger logger = LoggerFactory.getLogger(UnbenAsyncUncaughtExceptionHandler.class); /* (non-Javadoc) * @see org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler#handleUncaughtException(java.lang.Throwable, java.lang.reflect.Method, java.lang.Object[]) */ public void handleUncaughtException(Throwable ex, Method method, Object... params) { logger.error("#handleUncaughtException() - exception=[{}], method=[{}], params=[{}]", ex.getMessage(), method.getDeclaringClass() + "#" + method.getName(), StringUtils.join(params, ", ")); } }
2. 配置
<task:annotation-driven executor="asyncExecutor" exception-handler="unbenAsyncUncaughtExceptionHandler"/>