IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> SpringMvc 如何实现异步处理 -> 正文阅读

[Java知识库]SpringMvc 如何实现异步处理

在 SpringMvc 中为了方便使用异步请求专门提供了以下几种类型:

  1. AsyncWebRequest:专门来处理异步请求的,会将原来的 HttpServletRequest 类型做一层封装
  2. WebAsyncManager:spring mvc 异步请求处理过程中最核心的类型,管理着整个异步处理的过程
  3. WebAsyncUtils:异步工具类,用来获取 WebAsyncManager 以及创建 AsyncWebRequest 对象

在 SpringMvc 中,对异步请求的处理中提供了四个地方的支持:

1、FrameworkServlet 中给当前请求的 WebAsyncManager 添加了 CallableProcessingInterceptor 类型的拦截器->RequestBindingInterceptor,目的是为了在请求处理前将当前请求的 LocaleContext 和 ServletRequestAttributes 设置到 LocaleContextHolder 和 RequestContextHolder 中,并在请求处理完成后恢复,添加过程在 FrameworkServlet#processRequest 方法中

WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);	
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());

2、RequestMappingHandlerAdpater#invokeHandlerMethod 方法中提供了对异步请求的核心支持,其中做了时间跟异步处理相关的事情:

  • 创建 AsyncWebRequest,并设置了超时时间
  • 对当前请求的 WebAsyncManager 设置四个属性
  • 如果当前请求是异步请求而且已经处理出了结果,则将异步结果与之前保存到 WebAsyncManager 里的 ModelAndViewContainer 取出来,并将 WebAsyncManager 异步执行结果取出,然后调用 ServletInvocableHandlerMethod#wrapConcurrentResult 方法创建 ConcurrentResultHandlerMethod 子类来替换 ServletInvocableHandlerMethod,创建出来的 ConcurrentResultHandlerMethod 并不执行请求,主要是判断异步处理的结果是不是异常类型,如果是则抛出,如果不是则使用返回值处理器 HandlerMethodReturnValueHandler 对其进行解析并将处理后的结果返回
  • 如果 invokeAndHandler 方法执行完成后检查到当前请求已经启动了异步处理,则会直接返回 null
// 创建AsyncWebRequest异步请求对象
AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
asyncWebRequest.setTimeout(this.asyncRequestTimeout);

// 创建WebAsyncManager异步请求管理器对象
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.setTaskExecutor(this.taskExecutor);
asyncManager.setAsyncWebRequest(asyncWebRequest);
asyncManager.registerCallableInterceptors(this.callableInterceptors);
asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
// 如果当前异步请求已经处理并得到结果,则将返回的结果放到mavContainer对象中,然后将invocable对象进行包装转换,转成需要的执行对象然后开始执行
if (asyncManager.hasConcurrentResult()) {
  Object result = asyncManager.getConcurrentResult();
  mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
  asyncManager.clearConcurrentResult();
  LogFormatUtils.traceDebug(logger, traceOn -> {
    String formatted = LogFormatUtils.formatValue(result, !traceOn);
    return "Resume with async result [" + formatted + "]";
  });
  // 转换具体的invocable执行对象
  invocableMethod = invocableMethod.wrapConcurrentResult(result);
}

// 执行调用
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
  return null;
}

3、返回值处理器:一个有四个处理异步请求的返回值处理器,分别是 AsyncTaskMethodReturnValueHandler、CallableMethodReturnValueHandler、DeferredResultMethodReturnValueHandler、ListenableFutureReturnValueHandler,每一种对应一种类型的返回值,主要作用是使用 WebAsyncManager 启动异步处理.

4、在 DispatcherServlet#doDispatcher 方法中,当 HandlerAdpater 使用 handler 处理完请求时,会检查是否已经启动了异步处理器,如果启动了则不再往下处理,直接返回.

if (asyncManager.isConcurrentHandlingStarted()) {
  return null;
}

注意处理流程如下:首先在处理器中返回需要启动异步处理的类型时,相应的返回值处理器会调用 WebAsyncManager 相关方法启动异步处理,然后再 DispatcherServlet 中将原来请求直接返回,当异步处理完成后会重新发出一个相同的请求,这个是在 RequestMappingAdpater 中会使用特殊的 ServletInvoableHandlerMethod 来处理请求,处理方法是:如果是异步处理返回的结果是异常类型则抛出异常,否则直接返回异常处理结果,然后使用返回值处理器对其处理,接着返回 DispatcherServlet 中按正常流程往下处理.

WebAsyncTask、Callable 类型异步请求的处理过程及方法

当处理器方法返回 WebAsyncTask 或者 Callable 类型时,将自动启用异步处理,使用 WebAsyncTask 类型返回值的处理器 AsyncTaskMethodReturnValueHandler,如果返回值为 null,就会给 ModelAndViewContainer 设置为请求已处理,然后返回,如果返回值不为空,调用 WebAsyncManager#startCallableProcessing 方法处理请求,示例代码如下:

<servlet>
  <servlet-name>mvc-test</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <!--SpringMVC配置文件-->
  <init-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
  </init-param>
  <load-on-startup>1</load-on-startup>
  <async-supported>true</async-supported>
</servlet>
@Controller
public class AsyncTaskController {
    @ResponseBody
    @RequestMapping(value = "/webasynctask",produces = "text/plain; charset=UTF-8")
    public WebAsyncTask<String> webAsyncTask(){
        System.out.println("WebAsyncTask 处理器主线程进入");
        WebAsyncTask<String> task = new WebAsyncTask<String>(new Callable<String>() {
            @Override
            public String call() throws Exception {
                Thread.sleep(5*1000L);
                System.out.println("WebAsyncTask 处理执行中。。。");
                return "久等了";
            }
        });
        System.out.println("WebAsyncTask 处理器主线程退出");
        return task;
    }
}
public class AsyncCallableController {
    @ResponseBody
    @RequestMapping(value = "/callable",produces = "text/plain; charset=UTF-8")
    public Callable<String> callable(){
        System.out.println("Callable处理器主线程进入");
        Callable<String> callable = new Callable<String>() {
            @Override
            public String call() throws Exception {
                Thread.sleep(5 * 1000L);
                System.out.println("Callable处理执行中。。。");
                return "久等了";
            }
        };
        System.out.println("Callable处理器主线程退出");
        return callable;
    }
}

更多技术文章可以查看:vnjohn 个人博客

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-07-20 18:38:23  更:2022-07-20 18:42:24 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 12:58:53-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码