// 返回callable
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());{
return handleInternal(request, response, (HandlerMethod) handler);{
return mav = invokeHandlerMethod(request, response, handlerMethod);{
// 获取异步请求对象
AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
// 设置超时时间
asyncWebRequest.setTimeout(this.asyncRequestTimeout);
// 获取异步管理器
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);{
// 当请求对象是同一个的话,获取的WebAsyncManager就是同一个
// 在处理第一次处理请求的异步返回值的时候,就将WEB_ASYNC_MANAGER_ATTRIBUTE存进入了
// 然后当Tomcat再次分发请求的时候,携带的request是包装之后的request,org.apache.catalina.core.ApplicationHttpRequest,里面有一个request对象
// 就是包装的上次的请求对象RequestFacade
// 通过这个request请求对象,也能获取到WEB_ASYNC_MANAGER_ATTRIBUTE,因为这个获取getAttribute实在tomcat内部做的
// 所以前后两次的request对象可以理解为同一个
WebAsyncManager asyncManager = null;
Object asyncManagerAttr = servletRequest.getAttribute(WEB_ASYNC_MANAGER_ATTRIBUTE);
if (asyncManagerAttr instanceof WebAsyncManager) {
asyncManager = (WebAsyncManager) asyncManagerAttr;
}
// 没有就创建,所以,同一个请求只有一个WebAsyncManager
if (asyncManager == null) {
asyncManager = new WebAsyncManager();
servletRequest.setAttribute(WEB_ASYNC_MANAGER_ATTRIBUTE, asyncManager);
}
return asyncManager;
}
// 设置线程池
asyncManager.setTaskExecutor(this.taskExecutor);
// 设置AsyncWebRequest对象
asyncManager.setAsyncWebRequest(asyncWebRequest);
// 注册这两个返回值的拦截器
asyncManager.registerCallableInterceptors(this.callableInterceptors);
asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
// 判断是否已经有并发执行的结果,第一次执行肯定没有,但是第二次执行肯定有
// 因为这个异步任务执行完成的时候,设置了结果,才进行了再次发送请求操作
// 这就是为什么在handler方法,invokeHandlerMethod等等多个方法都会判断是否是异步操作,如果是异步操作就立刻return
// 就是因为执行异步任务会处理两次请求,第一次是正常执行,开启异步任务,第二次是获取异步任务结果,返回响应
if (asyncManager.hasConcurrentResult()) {
// 获取结果
Object result = asyncManager.getConcurrentResult();
// 获取到上次请求的mavContainer
mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
// 清空执行结果
asyncManager.clearConcurrentResult();
// 包装成ConcurrentResultHandlerMethod extends ServletInvocableHandlerMethod
invocableMethod = invocableMethod.wrapConcurrentResult(result);{
// ConcurrentResultHandlerMethod是一个Handler,内部包含Handler处理功能的Bean,和目标方法
// 所以,它将handler设置为Callable对象,方法是Callable的call方法
super((Callable<Object>) () -> {
if (result instanceof Exception) {
throw (Exception) result;
}
else if (result instanceof Throwable) {
throw new NestedServletException("Async processing failed", (Throwable) result);
}
return result;
}, CALLABLE_METHOD);
// 设置返回值处理器,因为拿到结果还需要处理返回值
if (ServletInvocableHandlerMethod.this.returnValueHandlers != null) {
setHandlerMethodReturnValueHandlers(ServletInvocableHandlerMethod.this.returnValueHandlers);
}
this.returnType = returnType;
}
}
// 第一次执行方法/或者异步返回值再次执行方法
invocableMethod.invokeAndHandle(webRequest, mavContainer){;
// 执行目标方法,得到返回结果
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
// 使用返回值处理器处理,其中就包装在HandlerAdapter中添加的两个
// handlers.add(new CallableMethodReturnValueHandler());
// handlers.add(new DeferredResultMethodReturnValueHandler());
// 第一次执行,被CallableMethodReturnValueHandler处理,因为方法返回的实Callable
// 第二次,得到任务的结果之后,就按照普通的请求处理返回值
this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);{
// 如果返回值为空,请求结束
if (returnValue == null) {
mavContainer.setRequestHandled(true);
return;
}
// 强转为callable
Callable<?> callable = (Callable<?>) returnValue;
// 使用异步管理器启动异步任务
// 所以,最终会将callable包装成WebAsyncTask对象,当返回结果是WebAsyncTask的时候,逻辑基本一样
// 使用的是AsyncTaskMethodReturnValueHandler的handleValue方法
// 也是调用 startCallableProcessing(new WebAsyncTask(callable), processingContext);启动
WebAsyncUtils.getAsyncManager(webRequest).startCallableProcessing(callable, mavContainer);{
startCallableProcessing(new WebAsyncTask(callable), processingContext);{
Long timeout = webAsyncTask.getTimeout();
// 设置超时时间
if (timeout != null) {
this.asyncWebRequest.setTimeout(timeout);
}
// 获取线程池,如果没有,打印警告日志,代码没展示
AsyncTaskExecutor executor = webAsyncTask.getExecutor();
if (executor != null) {
this.taskExecutor = executor;
}
// 添加拦截器
List<CallableProcessingInterceptor> interceptors = new ArrayList<>();
interceptors.add(webAsyncTask.getInterceptor());{
return new CallableProcessingInterceptor() {
@Override
public <T> Object handleTimeout(NativeWebRequest request, Callable<T> task) throws Exception {
return (timeoutCallback != null ? timeoutCallback.call() : CallableProcessingInterceptor.RESULT_NONE);
}
@Override
public <T> Object handleError(NativeWebRequest request, Callable<T> task, Throwable t) throws Exception {
return (errorCallback != null ? errorCallback.call() : CallableProcessingInterceptor.RESULT_NONE);
}
@Override
public <T> void afterCompletion(NativeWebRequest request, Callable<T> task) throws Exception {
if (completionCallback != null) {
completionCallback.run();
}
}
};
}
// asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
// org.springframework.web.servlet.FrameworkServlet.RequestBindingInterceptor
interceptors.addAll(this.callableInterceptors.values());
// CallableProcessingInterceptor timeoutCallableInterceptor = new TimeoutCallableProcessingInterceptor();
interceptors.add(timeoutCallableInterceptor);
// 获取任务
final Callable<?> callable = webAsyncTask.getCallable();
// 创建拦截器链
final CallableInterceptorChain interceptorChain = new CallableInterceptorChain(interceptors);
// 下面三个Handler,都是添加到StandardServletAsyncWebRequest中,而StandardServletAsyncWebRequest是一个AsyncListener监听器
// 当任务执行的时候,如果发布AsyncEvent事件,会被StandardServletAsyncWebRequest捕捉,指定对应的回调
// 在执行为完毕的时候,Tomcat内部会发布这个事件
// 执行org.apache.catalina.core.AsyncContextImpl.fireOnComplete的方法,最终会调用到下面类中对应的回调方法
// org.springframework.web.context.request.async.StandardServletAsyncWebRequest.onComplete
// 添加超时的handler,在AsyncManager中的asyncWebRequest属性中添加
// this.timeoutHandlers.add(timeoutHandler);
this.asyncWebRequest.addTimeoutHandler(() -> {
Object result = interceptorChain.triggerAfterTimeout(this.asyncWebRequest, callable);
if (result != CallableProcessingInterceptor.RESULT_NONE) {
setConcurrentResultAndDispatch(result);
}
});
// 添加处理错误的handler,在AsyncManager中的asyncWebRequest属性中添加
this.asyncWebRequest.addErrorHandler(ex -> {
if (!this.errorHandlingInProgress) {
Object result = interceptorChain.triggerAfterError(this.asyncWebRequest, callable, ex);
result = (result != CallableProcessingInterceptor.RESULT_NONE ? result : ex);
setConcurrentResultAndDispatch(result);
}
});
// 添加任务执行完成的Handler,在AsyncManager中的asyncWebRequest属性中添加
this.asyncWebRequest.addCompletionHandler(() -> interceptorChain.triggerAfterCompletion(this.asyncWebRequest, callable));
// 执行所有CallableProcessingInterceptor interceptor的applyBeforeConcurrentHandling方法
interceptorChain.applyBeforeConcurrentHandling(this.asyncWebRequest, callable);
// 启动异步任务
startAsyncProcessing(processingContext);{
synchronized (WebAsyncManager.this) {
// 标注结果为固定值
this.concurrentResult = RESULT_NONE;
this.concurrentResultContext = processingContext;
// 未发生错误
this.errorHandlingInProgress = false;
}
// 开启任务
this.asyncWebRequest.startAsync();{
// 调用Tomcat的开启异步任务方法
this.asyncContext = getRequest().startAsync(getRequest(), getResponse());
// 添加异步监听器,就是当前类StandardServletAsyncWebRequest,他是一个AsyncListener
// 有void onComplete(AsyncEvent event),void onTimeout(AsyncEvent event),void onError(AsyncEvent event)回调
this.asyncContext.addListener(this);
// 如果还有超时时间
if (this.timeout != null) {
// 设置超时时间
this.asyncContext.setTimeout(this.timeout);
}
}
}
try {
// 使用线程池执行任务
Future<?> future = this.taskExecutor.submit(() -> {
Object result = null;
try {
// 执行拦截器中applyPreProcess方法
interceptorChain.applyPreProcess(this.asyncWebRequest, callable);
// 任务执行
result = callable.call();
}
catch (Throwable ex) {
result = ex;
}
finally {
// 执行拦截器的的applyPostProcess
result = interceptorChain.applyPostProcess(this.asyncWebRequest, callable, result);
}
// 设置并发结果
setConcurrentResultAndDispatch(result);{
synchronized (WebAsyncManager.this) {
// 如果concurrentResult不等于表示结果已经设置过了
if (this.concurrentResult != RESULT_NONE) {
return;
}
// 设置最终结果
this.concurrentResult = result;
// 设置是否发生了错误
this.errorHandlingInProgress = (result instanceof Throwable);
}
// 判断异步任务是否完成
if (this.asyncWebRequest.isAsyncComplete()) {
return;
}
// 重新向Tomcat发送相同的请求,并且,请求对象不在是RequestFacade对象,而是org.apache.catalina.core.ApplicationHttpRequest对象
// 内部封装了上一次请求的RequestFacade对象,已经分发类型为ASYNC
this.asyncWebRequest.dispatch();
}
});
// 保存future,因为到时候拦截器可能会取消任务,例如超时的时候
interceptorChain.setTaskFuture(future);
}
catch (RejectedExecutionException ex) {
// 执行拦截器的applyPostProcess方法
Object result = interceptorChain.applyPostProcess(this.asyncWebRequest, callable, ex);
// 设置执行结果和重新发送同步请求
setConcurrentResultAndDispatch(result);
throw ex;
}
}
}
}
}
// 开启了异步Handler处理,就不往下执行了
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
}
}
}
// 对于handler方法,开启了异步Handler处理,就不往下执行了,如果是异步任务,因为任务还没执行完成
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
异步请求返回Callable和AsyncWebTask原理
于 2024-01-20 23:13:35 首次发布