当一个接口处理耗时时,为了接口做出快速相应,释放tomcat资源,提高系统的吞吐量,sping3.0 以后引入DeferredResult。
代码演示
@GetMapping("/deferredResult")
public DeferredResult<Map<String, Object>> test() {
System.out.println("进入" + Thread.currentThread() + Thread.currentThread().getId());
DeferredResult<Map<String, Object>> result = new DeferredResult<>();
new Thread(() -> {
System.out.println("开始" + Thread.currentThread());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("返回结果" + Thread.currentThread());
result.setResult(new HashMap<String, Object>() {{
put("code", "200");
}});
}).start();
System.out.println("返回" + Thread.currentThread() + Thread.currentThread().getId());
return result;
}
运行讲解
放入接口没有什么好理解的,就是一个纯粹的一个同步请求接口。主要关注的是对应的返回值为
DeferredResult
的接口,主要看看内部是如何进行执行的。从org.springframework.web.servlet.DispatcherServlet#doDispatch
执行开始进行。
- 经过
doDispatch
后,接下来会到对应的org.springframework.web.servlet.mvc.method.annotation.DeferredResultMethodReturnValueHandler#handleReturnValue
中,判断当前返回值类型。
@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
if (returnValue == null) {
mavContainer.setRequestHandled(true);
return;
}
DeferredResult<?> result;
if (returnValue instanceof DeferredResult) { // 本Demo中的数据类型
result = (DeferredResult<?>) returnValue;
}
else if (returnValue instanceof ListenableFuture) { // 原有Future的增强
result = adaptListenableFuture((ListenableFuture<?>) returnValue);
}
else if (returnValue instanceof CompletionStage) { // 用于异步执行中的阶段处理
result = adaptCompletionStage((CompletionStage<?>) returnValue);
}
else {
// Should not happen...
throw new IllegalStateException("Unexpected return value type: " + returnValue);
}
WebAsyncUtils.getAsyncManager(webRequest).startDeferredResultProcessing(result, mavContainer); // 获得对应异步管理器并执行
}
复制代码
- 经过包装返回值的类型,接下来就进行到了请求处理:
org.springframework.web.context.request.async.WebAsyncManager#startDeferredResultProcessing
public void startDeferredResultProcessing(
final DeferredResult<?> deferredResult, Object... processingContext) throws Exception {
Assert.notNull(deferredResult, "DeferredResult must not be null");
Assert.state(this.asyncWebRequest != null, "AsyncWebRequest must not be null");
Long timeout = deferredResult.getTimeoutValue();
if (timeout != null) {
this.asyncWebRequest.setTimeout(timeout);
}
// 增加拦截器设置 此时只有第一个和第三个(第一个是DeferredResult类中匿名实现)
List<DeferredResultProcessingInterceptor> interceptors = new ArrayList<>();
interceptors.add(deferredResult.getInterceptor());
interceptors.addAll(this.deferredResultInterceptors.values());
interceptors.add(timeoutDeferredResultInterceptor);
final DeferredResultInterceptorChain interceptorChain = new DeferredResultInterceptorChain(interceptors);
// 增加超时 错误 完成回调处理,进行触发
this.asyncWebRequest.addTimeoutHandler(() -> {
try {
interceptorChain.triggerAfterTimeout(this.asyncWebRequest, deferredResult);
}
catch (Throwable ex) {
setConcurrentResultAndDispatch(ex);
}
});
this.asyncWebRequest.addErrorHandler(ex -> {
if (!this.errorHandlingInProgress) {
try {
if (!interceptorChain.triggerAfterError(this.asyncWebRequest, deferredResult, ex)) {
return;
}
deferredResult.setErrorResult(ex);
}
catch (Throwable interceptorEx) {
setConcurrentResultAndDispatch(interceptorEx);
}
}
});
this.asyncWebRequest.addCompletionHandler(()
-> interceptorChain.triggerAfterCompletion(this.asyncWebRequest, deferredResult));
// 请求初始之前的处理 -空实现
interceptorChain.applyBeforeConcurrentHandling(this.asyncWebRequest, deferredResult);
// 开始异步调用处理
startAsyncProcessing(processingContext);
try {
//
interceptorChain.applyPreProcess(this.asyncWebRequest, deferredResult);
deferredResult.setResultHandler(result -> {
result = interceptorChain.applyPostProcess(this.asyncWebRequest, deferredResult, result);
setConcurrentResultAndDispatch(result);
});
}
catch (Throwable ex) {
setConcurrentResultAndDispatch(ex);
}
}
复制代码
- 请求接着往下走,会进行到
org.apache.catalina.core.AsyncContextImpl#setStarted
。在其中进行异步事件处理。
public void setStarted(Context context, ServletRequest request,
ServletResponse response, boolean originalRequestResponse) {
synchronized (asyncContextLock) {
this.request.getCoyoteRequest().action(ActionCode.ASYNC_START, this); // 异步事件处理 - 钩子函数
this.context = context;
context.incrementInProgressAsyncCount();
this.servletRequest = request;
this.servletResponse = response;
this.hasOriginalRequestAndResponse = originalRequestResponse;
this.event = new AsyncEvent(this, request, response);
// 注册异步事件监听器 - 当前为空 不进行监听
List<AsyncListenerWrapper> listenersCopy = new ArrayList<>(listeners);
listeners.clear();
if (log.isDebugEnabled()) {
log.debug(sm.getString("asyncContextImpl.fireOnStartAsync"));
}
for (AsyncListenerWrapper listener : listenersCopy) {
try {
listener.fireOnStartAsync(event);
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
log.warn(sm.getString("asyncContextImpl.onStartAsyncError",
listener.getClass().getName()), t);
}
}
}
}
复制代码
- 当异步事件处理完成之后,则会还需要对应
Dispatch
进行响应。
private void setConcurrentResultAndDispatch(Object result) {
synchronized (WebAsyncManager.this) {
if (this.concurrentResult != RESULT_NONE) {
return;
}
this.concurrentResult = result;
this.errorHandlingInProgress = (result instanceof Throwable);
}
if (this.asyncWebRequest.isAsyncComplete()) {
if (logger.isDebugEnabled()) {
logger.debug("Async result set but request already complete: " + formatRequestUri());
}
return;
}
if (logger.isDebugEnabled()) {
boolean isError = result instanceof Throwable;
logger.debug("Async " + (isError ? "error" : "result set") + ", dispatch to " + formatRequestUri());
}
this.asyncWebRequest.dispatch(); // ASYNC_DISPATCH事件注册
}
复制代码
- 判断当前请求是否超时逻辑
org.apache.coyote.AbstractProcessor#timeoutAsync
:
@Override
public void timeoutAsync(long now) {
if (now < 0) {
doTimeoutAsync();
} else {
long asyncTimeout = getAsyncTimeout();
if (asyncTimeout > 0) {
long asyncStart = asyncStateMachine.getLastAsyncStart();
if ((now - asyncStart) > asyncTimeout) {
doTimeoutAsync();
}
} else if (!asyncStateMachine.isAvailable()) {
// Timeout the async process if the associated web application
// is no longer running.
doTimeoutAsync();
}
}
}
private void doTimeoutAsync() {
// Avoid multiple timeouts
setAsyncTimeout(-1);
asyncTimeoutGeneration = asyncStateMachine.getCurrentGeneration();
processSocketEvent(SocketEvent.TIMEOUT, true); // 发送timeout事件
}
复制代码
HTTP
事件响应可以看看org.apache.coyote.AbstractProcessor#action
类中,针对HTTP各种事件进行各种处理(code太多,这里就不贴了)。