spring3支持@Async註解的異步任務,之前大家都是通過使用如線程池來完成,spring3也是使用這種方式,但更簡單。
其具體實現在:org.springframework.aop.interceptor.AsyncExecutionInterceptor,是一個方法攔截器,其invoke方法的部分代碼如下:
Future<?> result = determineAsyncExecutor(specificMethod).submit(
new Callable<Object>() {
public Object call() throws Exception {
try {
Object result = invocation.proceed();
if (result instanceof Future) {
return ((Future<?>) result).get();
}
}
catch (Throwable ex) {
ReflectionUtils.rethrowException(ex);
}
return null;
}
});
即把當前任務的調用提交給線程池,很簡單。
1、測試無事務的異步任務
這個相對來說比較簡單:
1.1、設置任務的返回值爲Future:
public Future sendSystemMessage(Long[] receiverIds, Message message);
1.2、調用future.get();等待任務結束。
Future future = messageApi.sendSystemMessage(userIds, message);
future.get();
這個很簡單。
2、測試帶事務的異步任務
因爲是帶事務的,所以異步任務肯定要啓動一個線程來執行任務,所以無法在主線程回滾,造成數據會commit到數據庫,這在集成測試時肯定是不行的;解決方案是移除異步任務:
2.1、使用spring profile,在測試環境下不執行<task:annotation-driven>即可。
2.2、使用我提供的工具類,在測試時移除異步支持即可:
//移除異步支持
if(AopProxyUtils.isAsync(messageApi)) {
AopProxyUtils.removeAsync(messageApi);
}
測試類可以參考MessageApiServiceIT.java
工具類下載 AopProxyUtils.java
3、包級別測試
@Async
public void sendSystemMessage() {
sendSystemMessageInner();
}
void sendSystemMessageInner() {
//測試時測試這個方法即可
}
這樣測試時測試這個包級別的sendSystemMessageInner方法即可
其實更好的做法是spring內部提供支持,支持這樣異步調用的測試。