1. 程式人生 > 其它 >@async 預設執行緒池_Spring 原始碼學習 @Async註解實現原理

@async 預設執行緒池_Spring 原始碼學習 @Async註解實現原理

技術標籤:@async 預設執行緒池@async註解@order註解exceptionhandler註解java註解的實現原理notnull註解

本文作者:geek,一個聰明好學的朋友

1. 簡介

開發中我們需要非同步執行某個耗時任務時候需要@Async,以下我將從原始碼角度解釋該註解的實現原理。

2.前提條件@EnableAsync

專案使用中,需要新增@EnableAsync註解支援,才能使用@Async(也支援自定義註解)生效。@EnableAsync(預設mode為AdviceMode.PROXY情況下)作用為了給spring專案加入AsyncConfigurationSelector,從而引入AsyncAnnotationBeanPostProcessor。

@Import(AsyncConfigurationSelector.class)
public@interfaceEnableAsync{}
publicclassProxyAsyncConfigurationextendsAbstractAsyncConfiguration{

@Bean(name=TaskManagementConfigUtils.ASYNC_ANNOTATION_PROCESSOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
publicAsyncAnnotationBeanPostProcessorasyncAdvisor(){
Assert.notNull(this.enableAsync,"@EnableAsyncannotationmetadatawasnotinjected");
/**
*建立postProcessor,支援定製executor與exceptionHandler
*/
AsyncAnnotationBeanPostProcessorbpp=newAsyncAnnotationBeanPostProcessor();
bpp.configure(this.executor,this.exceptionHandler);
ClassextendsAnnotation>customAsyncAnnotation=this.enableAsync.getClass("annotation");
if(customAsyncAnnotation!=AnnotationUtils.getDefaultValue(EnableAsync.class,"annotation")){
bpp.setAsyncAnnotationType(customAsyncAnnotation);
}
bpp.setProxyTargetClass(this.enableAsync.getBoolean("proxyTargetClass"));
bpp.setOrder(this.enableAsync.getNumber("order"));returnbpp;
}
}

3.AsyncAnnotationBeanPostProcessor的作用

AsyncAnnotationBeanPostProcessor為加了@Async註解的方法的目標類加入AsyncAnnotationAdvisor。AsyncAnnotationAdvisor也即是spring AOP中責任鏈呼叫的advisor,可見被@Async的實現是通過生成代理物件來實現的。
publicclassAsyncAnnotationBeanPostProcessorextendsAbstractBeanFactoryAwareAdvisingPostProcessor{

@Override
publicvoidsetBeanFactory(BeanFactorybeanFactory){
super.setBeanFactory(beanFactory);

AsyncAnnotationAdvisoradvisor=newAsyncAnnotationAdvisor(this.executor,this.exceptionHandler);
if(this.asyncAnnotationType!=null){
advisor.setAsyncAnnotationType(this.asyncAnnotationType);
}
advisor.setBeanFactory(beanFactory);
this.advisor=advisor;
}

}
publicclassAsyncAnnotationAdvisorextendsAbstractPointcutAdvisorimplementsBeanFactoryAware{
publicAsyncAnnotationAdvisor(
@NullableSupplierexecutor,@NullableSupplierexceptionHandler){

/**
*支援Async與Asynchronous
*/
Set>asyncAnnotationTypes=newLinkedHashSet<>(2);
asyncAnnotationTypes.add(Async.class);try{
asyncAnnotationTypes.add((ClassextendsAnnotation>)
ClassUtils.forName("javax.ejb.Asynchronous",AsyncAnnotationAdvisor.class.getClassLoader()));
}catch(ClassNotFoundExceptionex){//IfEJB3.1APInotpresent,simplyignore.
}this.advice=buildAdvice(executor,exceptionHandler);this.pointcut=buildPointcut(asyncAnnotationTypes);
}/**
*//這個最終又是委託給`AnnotationAsyncExecutionInterceptor`,它是一個具體的增強器,有著核心內容
*@paramexecutor
*@paramexceptionHandler
*@return
*/protectedAdvicebuildAdvice(
@NullableSupplierexecutor,@NullableSupplierexceptionHandler){
AnnotationAsyncExecutionInterceptorinterceptor=newAnnotationAsyncExecutionInterceptor(null);
interceptor.configure(executor,exceptionHandler);returninterceptor;
}
}

4.AnnotationAsyncExecutionInterceptor核心內容

AnnotationAsyncExecutionInterceptor繼承AsyncExecutionInterceptor間接實現了MethodInterceptor,該攔截器的實現的invoke方法把原來方法的呼叫提交到新的執行緒池執行,從而實現了方法的非同步。當需要獲得非同步結果時,支援CompletableFuture,ListenableFuture,Future的返回。

publicclassAsyncExecutionInterceptorextendsAsyncExecutionAspectSupportimplementsMethodInterceptor,Ordered{@Override
@Nullable
publicObjectinvoke(finalMethodInvocationinvocation)throwsThrowable{
Class>targetClass=(invocation.getThis()!=null?AopUtils.getTargetClass(invocation.getThis()):null);
MethodspecificMethod=ClassUtils.getMostSpecificMethod(invocation.getMethod(),targetClass);
finalMethoduserDeclaredMethod=BridgeMethodResolver.findBridgedMethod(specificMethod);

AsyncTaskExecutorexecutor=determineAsyncExecutor(userDeclaredMethod);
if(executor==null){
thrownewIllegalStateException(
"NoexecutorspecifiedandnodefaultexecutorsetonAsyncExecutionInterceptoreither");
}
/**
*構建放到AsyncTaskExecutor執行CallableTask
*/
Callabletask=()->{try{
Objectresult=invocation.proceed();if(resultinstanceofFuture){return((Future>)result).get();
}
}catch(ExecutionExceptionex){
handleError(ex.getCause(),userDeclaredMethod,invocation.getArguments());
}catch(Throwableex){
handleError(ex,userDeclaredMethod,invocation.getArguments());
}returnnull;
};returndoSubmit(task,executor,invocation.getMethod().getReturnType());
}
}

5. 使用注意事項

5.1使用@Aysnc的時候最好配置一個執行緒池Executor以讓執行緒複用節省資源,或者為SimpleAsyncTaskExecutor設定基於執行緒池實現的ThreadFactory,在否則會預設使用SimpleAsyncTaskExecutor,該executor會在每次呼叫時新建一個執行緒。

/**
*SimpleAsyncTaskExecutor繼承自CustomizableThreadCreator,可以看到執行緒直接new
*/
publicclassCustomizableThreadCreatorimplementsSerializable{
publicThreadcreateThread(Runnablerunnable){
Threadthread=newThread(getThreadGroup(),runnable,nextThreadName());
thread.setPriority(getThreadPriority());
thread.setDaemon(isDaemon());
returnthread;
}
}

5.2關於方法內部呼叫,@Async註解會失效

publicclassQueryServiceImplimplementsQueryService{
@Override
publicvoidA(){
System.out.println("QueryServiceImpl.A");
B();
}

@Async
@Override
publicvoidB(){
System.out.println("QueryServiceImpl.B");
}
}

失效原因:A方法中呼叫B方法,呼叫即為this.B(),this物件為原始的物件,並不是增強後代理物件,當然不能生效了。建議重構分開呼叫,如果硬是需要內部呼叫則是隻能通過獲取代理物件來實現。

@Component("q")
publicclassQueryServiceImplimplementsQueryService{

@Autowired
privateApplicationContextapplicationContext;


@Override
publicvoidA(){
System.out.println("QueryServiceImpl.A");
QueryServicequeryService=(QueryService)applicationContext.getBean("q");
queryService.B();
}

@Async
@Override
publicvoidB(){
System.out.println("QueryServiceImpl.B");
}
}

參考

  • 【小家Spring】Spring非同步處理@Async的使用以及原理、原始碼分析(@EnableAsync))

檢視更多文章關注公眾號:好奇心森林cbc56fade8a8f4ace70acb7e637d971c.png