说异步调用
前,咱们说说它对应的同步调用
。一般开发过程当中,通常上咱们都是同步调用
,即:程序按定义的顺序依次执行的过程,每一行代码执行过程必须等待上一行代码执行完毕后才执行。而异步调用
指:程序在执行时,无需等待执行的返回值可继续执行后面的代码。显而易见,同步有依赖相关性,而异步没有,因此异步可并发
执行,可提升执行效率,在相同的时间作更多的事情。html
回调:处理异步
、同步
外,还有一个叫回调
。其主要是解决异步方法执行结果的处理方法,好比在但愿异步调用结束时返回执行结果,这个时候就能够考虑使用回调机制。前端
在编写实际代码以前,咱们来了解下一些关于异步请求的api的调用说明。java
HttpServletRequest
对象获取。
1
|
AsyncContext asyncContext = request.startAsync();
|
其监听器的接口代码:web
1
2
3
4
5
6
|
public
interface
AsyncListener
extends
EventListener {
void
onComplete(AsyncEvent event)
throws
IOException;
void
onTimeout(AsyncEvent event)
throws
IOException;
void
onError(AsyncEvent event)
throws
IOException;
void
onStartAsync(AsyncEvent event)
throws
IOException;
}
|
说明:spring
通常上,咱们在超时或者异常时,会返回给前端相应的提示,好比说超时了,请再次请求等等,根据各业务进行自定义返回。同时,在异步调用完成时,通常须要执行一些清理工做或者其余相关操做。api
须要注意的是只有在调用request.startAsync
前将监听器添加到AsyncContext
,监听器的onStartAsync
方法才会起做用,而调用startAsync
前AsyncContext
还不存在,因此第一次调用startAsync
是不会被监听器中的onStartAsync
方法捕获的,只有在超时后又从新开始的状况下onStartAsync
方法才会起做用。并发
setTimeout
方法设置,单位:毫秒。必定要设置超时时间,不能无限等待下去,否则和正常的请求就同样了。。app
package com.example.demo.Servlet; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.AsyncContext; import javax.servlet.AsyncEvent; import javax.servlet.AsyncListener; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * 使用Servlet方式进行异步请求 */ @Slf4j @RestController public class ServletController { @RequestMapping(value = "/servlet/orig") public void todo(HttpServletRequest request, HttpServletResponse response) throws InterruptedException, IOException { response.setContentType("ext/html;charset=UTF-8"); Thread.sleep(1000); response.getWriter().print("这是【正常】的请求返回"); } @RequestMapping(value = "/servlet/async") public void todoAsync(HttpServletRequest request, HttpServletResponse response) { AsyncContext asyncContext = request.startAsync(); asyncContext.addListener(new AsyncListener() { @Override public void onComplete(AsyncEvent asyncEvent) throws IOException { log.info("执行完成"); } @Override public void onTimeout(AsyncEvent asyncEvent) throws IOException { log.info("超时了"); } @Override public void onError(AsyncEvent asyncEvent) throws IOException { log.info("发生错误"); } @Override public void onStartAsync(AsyncEvent asyncEvent) throws IOException { log.info("线程开始"); } }); asyncContext.setTimeout(20000); asyncContext.start(() -> { try { Thread.sleep(10000); System.out.println("ddddd"); log.info("内部线程:"+Thread.currentThread().getName()); asyncContext.getResponse().setCharacterEncoding("utf-8"); asyncContext.getResponse().setContentType("text/html;charset=UTF-8"); asyncContext.getResponse().getWriter().print("这是【异步】的请求返回"); }catch (Exception e){ log.error("异常",e); } //异步请求完成通知 //此时整个请求才完成 //其实能够利用此特性 进行多条消息的推送 把链接挂起。。 asyncContext.complete(); }); System.out.println("main方法线程"); //此时之类 request的线程链接已经释放了 log.info("线程:" + Thread.currentThread().getName()); } }
注意:异步请求时,能够利用ThreadPoolExecutor
自定义个线程池。异步
1.启动下应用,查看控制台输出就能够获悉是否在同一个线程里面了。同时,可设置下等待时间,以后就会调用超时回调方法了。你们可本身试试。async