一.SpringWebFlux基础知识
1.概念
- Spring5提出的新的开发Web的技术栈,非阻塞的开发模式,运行在netty或servlet3.1上,支持很高的并发量
- 非阻塞的概念
- WebFlux一个线程里可以处理更多的请求
- 老的开发模式:一个请求会对应容器里的一个线程
- 运行环境的不同
- 老的开发模式:基于ServletAPI,即运行在Servlet容器上面
- Webflux开发模式:基于响应式流,可以运行在Servlet3.1之后的容器(异步Servlet容器)或Netty上
- 数据库的不同
- 目前关系型数据库都是不支持响应式(基于JDBC)的数据库
- Reactive stack的SpringDataReactiveRepositories是:Mongo,Cassandra,Redis,Couchbase
2. 开发优势
- 支持高并发(异步非阻塞模式——垂直扩展)
【题外知识:扩展分为两部分水平扩展和垂直扩展,水平扩展指的是人员和硬件设备的增加,垂直扩展只的是技术栈的变更】
二.异步Servlet
1.为什么要使用异步Servlet?同步Servlet阻塞了什么?
- 同步Servlet代码
@WebServlet("/SyncServlet")
public class SyncServlet extends HttpServlet {
public SyncServlet() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse) {
//获取进入时时间
long t1 = System.currectTimeMillis();
//执行业务代码
doSomeThing(request, response);
//打印执行耗时
System.out.println("Sync use:"+(System.currectTimeMillis()-t1));
}
protected void doPost(HttpServletRequest request, HttpServletResponse) {
doGet(request, response);
}
//耗时操作执行逻辑
public void doSomeThing(HttpServletRequest request, HttpServletResponse) {
//模拟耗时操作
try {
TimeUnit.SECONDS.sleep(5);//延迟5秒
} catch(InterruptedException e) {
}
response.getWriter().append("done");
}
}
//访问请求大约耗时5s
- 同步Servlet阻塞了Tomcat容器的servlet线程。
- 请求执行流程:当网络请求发送到Tomcat容器之后,Tomcat容器会给每一个请求创建一个线程去处理,线程里会调用指定Servlet去处理。当使用同步Servlet时,业务代码花多长时间,Servlet代码就要等多长时间。
- 异步Servlet代码[不会阻塞Tomcat的Servlet线程]
@WebServlet(asyncSupported=true, urlPatterns={
"/AsyncServlet"})
public class AsyncServlet extends HttpServlet {
public AsyncServlet() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse) {
//获取进入时时间
long t1 = System.currectTimeMillis();
//开启异步,获得异步执行的上下文
AsyncContext asyncContext = request.startAsync();
//使用JDK8的CompletableFuture.runAsync(()->...);的方式执行异步操作在不同线程里处理[执行业务代码,传递异步执行的上下文请求及响应]
CompletableFuture.runAsync(()->doSomeThing(asyncContext,asyncContext.getRequest(), asyncContext.getResponse()));
//打印执行耗时
System.out.println("Async use:"+(System.currectTimeMillis()-t1));
}
protected void doPost(HttpServletRequest request, HttpServletResponse) {
doGet(request, response);
}
//耗时操作执行逻辑
public void doSomeThing(AsyncContext asyncContext,ServletRequest request, ServletResponse) {
//模拟耗时操作
try {
TimeUnit.SECONDS.sleep(5);//延迟5秒
} catch(InterruptedException e) {
}
response.getWriter().append("done");
//业务代码处理完毕,通知结束
asyncContext.complete();
}
}
//访问请求大约耗时16ms
2.异步Servlet怎样编写
- 开启异步上下文
- 将异步代码放到独立的线程池中执行
- 调用异步上下文的complete()方法通知结束
三.WebFlux开发
1.Mono对象实战开发
-
添加Reactive Web依赖
-
实例代码
@RestController public class TestController { @GetMapping("/1") private String get1() { return "some string"; } @GetMapping("/2") private Mono<String> get2() { Mono<String>result = Mono.fromSupplier(()->"some string"); //返回Mono不会阻塞线程,如果是耗时操作会异步执行