Spring响应式微服务学习-Web框架Spring WebFlux

前言
   目前Spring boot2.0技术栈分为了2个技术体系,一种是响应式技术栈,一种是传统Servlet技术栈。如下图:

image.png

   在构建微服务的时候,我们可以根据情况来决定3种架构方式:
1、完全响应式
这种方式就是从网关到基础设施层,使用的都是响应式的框架,但目前数据库方面只支持mongo和Cassandra及redis等,如果有用到mysql的场景则暂时不适用。
2、混合式
由于使用部分数据库的场景是无法使用响应式的,比如mysql,所以在mysql以外的部分可以采用响应式。
3、完全命令式
  使用Servlet Stack,对所有组件都支持。
最后总结响应式和命令式的优缺点:
  优点:在IO密集型场景时,虽然代码运行性能不会提升,但可以有效的提升吞吐量,比如请求数据库,或者微服务中下游服务响应比较长,当你进行一个请求时,会用一个Pushlisher来替代阻塞的过程,调用者可以注册这个Pushlisher,这样的话,在之后数据库或下一层服务返回结果的时候,就会通知Publisher,然后Publisher会通知调用者。
  缺点:写入的代码和执行的代码分离开来,导致阅读和编写代码的难度增加,对于这种异步的代码,编写单元测试和调试代码都很困难。
  在之前进行微服务架构的实践中,本人也是使用了第2种微服务架构方式,也就是混合式,使用spring cloud gateway作为网关,gateway是一款基于Spring WebFlux的网关组件,所以也是对WebFlux做了一下研究,并为后续的构建响应式微服务打好基础。

对比传统的Spring WebMVC和响应式Spring WebFlux

image.png

  在图中,左侧为spring-webmvc的技术栈,右侧为spring-webflux的技术栈。Spring WebFlux是基于响应式流的,因此,可以建立异步的、非阻塞的、事件驱动的服务。它采用Reactor作为首选的响应式流的实现库,并且也提供了对RxJava的支持。而传统的Spring WebMVC构建在Java EE的servlet标准之上,该标准本身就是阻塞式和同步的。在最新版的Servlet中也添加了异步支持,但是在等待请求的过程中,Servlet仍然在线程池中保持着线程。
Spring-WebFlux可以运行在Tomcat,Jetty,Netty,Undertow,Servlet3.1+等多个容器上,默认使用Netty。这里要提一个在Spring cloud gateway使用时遇到的容器的坑,gateway只能运行在netty上,否则qps会大大下降。参照我的文章:https://www.jianshu.com/p/dde1b00cbbaa

Spring MVC和Spring WebFlux的关系
  请看下图,既有共同的部分,也有互相独立的部分。

image.png

WebFlux的使用场景
  在微服务架构体系中,WebFlux和WebMVC可以混合使用。而在IO密集型服务时,我们可以优先选择WebFlux去实现。比如web网关spring cloud gateway就是使用了基于WebFlux的实现,在运行时间上,响应式和非阻塞并不能让程序运行的更快,相反还要稍微增加一些处理时间,可能还会稍微变慢,那么gateway为什么要用它呢,因为网关是一个IO密集型服务,如果下层服务的网络变慢或不可靠,那么响应式所能体现出来的巨大差异就显示出来了。

说回WebFlux
  前边说过WebFlux采用Reactor作为首选的响应式流的实现库,Mono和Flux是Reactor中两个基础概念,Mono包含了0..1个元素序列,Flux包含了0..N个元素序列。Mono和Flux都是发布者,实现了Publisher。在WebFlux中,方法只返回Mono和Flux,代码基本也只和 Mono 或 Flux 打交道。而 Web Flux 则会实现 Subscriber ,onNext 时将业务开发人员编写的 Mono 或 Flux 转换为 HTTP Response 返回给客户端。WebFlux有两种不同的编程风格,分别是基于Spring MVC的注解和基于函数式路由。

基于Spring MVC

@RestController
public class HelloController {
    @RequestMapping("sayOneHello")
    public Mono sayOneHello() {
        return Mono.just("Hello World");
    }

    @RequestMapping("sayMoreHello")
    public Flux sayMoreHello() {
        return Flux.fromIterable(new ArrayList() {
            {
                add("Hello World one");
                add("Hello World two");
                add("Hello World three");
            }
        });
    }
}

基于函数式路由

@Component
public class HelloWorldHandlerFunction {

    public Mono hello(ServerRequest serverRequest) {
        return ServerResponse.ok().contentType(MediaType.TEXT_PLAIN).body(
                BodyInserters.fromValue("Hello World"));
    }
}

@Configuration
public class HelloWorldRouter {
    @Bean
    public RouterFunction routeHelloWorld(HelloWorldHandlerFunction helloWorldHandlerFunction) {
        return RouterFunctions.route(RequestPredicates.GET("/hello").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)),
                helloWorldHandlerFunction::hello);
    }
}

你可能感兴趣的:(Spring响应式微服务学习-Web框架Spring WebFlux)