理解WebFlux

Spring Webflux是一个无阻塞web框架,它适合处理大量并发连接,可以更有效率的利用多核cpu,这篇博客主要讲述WebFlux是什么和MVC有什么区别.

在这里插入图片描述

为什么WebFlux是无阻塞框架

WebFlux采用的是NIO模型,而java采用的IO模型

NIO

从下图来看,在请求过来时首先经过Selector,Selector会不断的轮询注册在上面的所有channel,并找到普配的channel并把任务交给他.每当完成就返回给Selector,这时一个现成就可以同时处理多个任务,其中nio的read/write是非阻塞的

在这里插入图片描述

IO

由于Java IO是阻塞的,所以当面对多个流的读写时需要多个线程处理。例如在网络IO中,Server端使用一个线程监听一个端口,一旦某个连接被accept,创建新的线程来处理新建立的连接。其中 read/write 是阻塞的。

在这里插入图片描述

总结

IO中高并发的场景,经常会使用ThreadPool去处理任务,但这种情况其实也是阻塞io.因为当thread pool中没有线程时,其他任务只能等线程空闲.但NIO不存在这个问题.所以webFlux是非阻塞的,它更适合高并发的场景.

Reactive Stream

在这里插入图片描述

Reactive Stream诞生于JDK9.reactive stream就是一个异步stream处理的标准,它的特点就是非阻塞的back pressure。reactive stream只是一个标准,它定义了实现非阻塞的back pressure的最小区间的接口,方法和协议。在JDK给的实现叫FlowAPI
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zYlmLBll-1599730454759)(https://tech.taiji.com.cn/ui/api/upload/a373be93840c4a8fac5c3d90030b454c_-_1599704667.jpg)]

  • Subscription 接口定义了连接发布者和订阅者的方法,主要的作用是为发布者和订阅者建立关系
  • Publisher 接口定义了发布者的方法;
  • Subscriber 接口定义了订阅者的方法;
  • Processor<T,R> 接口定义了处理器;

订阅者 Subscriber

Subscriber 订阅 Publisher 的数据流,并接受回调。 如果 Subscriber 没有发出请求,就不会受到数据。对于给定订阅(Subscription),调用 Subscriber 的方法是严格按顺序的。方法如下所示:

        Subscriber<Integer> subscriber = new Subscriber<Integer>() {
            private Subscription subscription;
            //建立订阅关系
            @Override
            public void onSubscribe(Subscription subscription) {

                this.subscription = subscription;
                //已经准备好索要数据
                this.subscription.request(1);
            }

            //处理接收数据
            @Override
            public void onNext(Integer integer) {
                //处理数据
                System.out.println("接收到数据 "+ integer);
                //处理完成继续要数据
                this.subscription.request(1);

            }

            @Override
            public void onError(Throwable throwable) {
                //数据处理异常
                this.subscription.cancel();
            }

            @Override
            public void onComplete() {
                //数据全部处理完成
                this.subscription.cancel();

            }
        };

订阅Subscription

Subscription 用于连接 Publisher 和 Subscriber。Subscriber 只有在请求时才会收到项目,并可以通过 Subscription 取消订阅。Subscription 主要有两个方法:

  • request:订阅者调用此方法请求数据;
  • cancel:订阅者调用这个方法来取消订阅,解除订阅者与发布者之间的关系。

发布者 Publisher

Publisher 将数据流发布给注册的 Subscriber。它通常使用 Executor 异步发布项目给订阅者。 Publisher 需要确保每个订阅的 Subscriber 方法严格按顺序调用。subscribe 方法用于订阅者订阅发布者。

处理器 Processor

Processor 位于 Publisher 和 Subscriber 之间,用于做数据转换。可以有多个 Processor 同时使用,组成一个处理链,链中最后一个处理器的处理结果发送给 Subscriber。JDK 没有提供任何具体的处理器。处理器同时是订阅者和发布者,接口的定义也是继承了两者,作为订阅者接收数据,然后进行处理,处理完后作为发布者,再发布出去。

背压 back pressure

在传统的消息推送机制中主要有两种方法 pull push,pull 面临的问题是当你去拉取数据,数据可能没有准备好.而push的问题是,不知道消费者到地能不能处理push过去的数据,如果数据量过大会造成消费者崩溃.所谓的背压,就是Subscriber告诉Publisher我要多少数据你给我发过来,也就是下图所示Request N item的过程.

在这里插入图片描述

WebFlux

从下图来看,webFlux支持函数式便程,Netty以及Event loop

在这里插入图片描述

  • WebFlux是Spring推出响应式编程的一部分(web端)
  • 响应式编程是异步非阻塞的(是一种基于数据流(data stream)和变化传递(propagation of change)的声明式(declarative)的编程范式)

Event loop

Event loop 是一种事件轮询机制,主要是为了解决单线程情况下啊,事件阻塞的问题.JavaScript用的就是Event loop,举个例子,前端进行渲染时,往往可能需要请求多个数据,同时才做Dom对象,如果是阻塞的,那所有的任务都只能排好队一个个执行,这会导致效率极其低下,但event loop 就是分发任务,不断的轮询,拿到结果,多个任务页面同时进行.个人觉得就是多路IO.

上面说到的Selector她的主要作用就是Event loop 监控多个channel.

Reactor

WebFlux使用的响应式流并不是用JDK9平台的,而是一个叫做Reactor响应式流库。所以,入门WebFlux其实更多是了解怎么使用Reactor的API,下面我们来看看~

Reactor是一个响应式流,它也有对应的发布者(Publisher ),Reactor的发布者用两个类来表示:

  • Mono(返回0或1个元素)
  • Flux(返回0-n个元素)

Mono 一次性返回所有数据

Flux 可以实现间隔一段时间返回数据

下面通过代码来认识一下webflux

    @GetMapping(value = "/2" )
    public Mono<String> test2() throws InterruptedException {
        log.info("start");
        TimeUnit.SECONDS.sleep(5);
        Mono<String> stringMono = Mono.fromSupplier(() -> createStr());
        log.info("end");
        return stringMono;
    }

从调用者(浏览器)的角度而言,是感知不到有什么变化的,因为都是得等待5s才返回数据。但是,从服务端的日志我们可以看出,WebFlux是直接返回Mono对象的 但是mvc的项目会阻塞5秒

在这里插入图片描述

事件推送

正常的请求都是一问一答的模式,但是事件推送(SSE -> Server Send Event)可以做到连续返回数据.下面代码的效果就是连续的返回数据.

示例代码
    @GetMapping(value = "/3",produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> test3() {
        log.info("start");
        Flux<String> stringMono = Flux.fromStream(IntStream.range(1,5).mapToObj(i ->{
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "flux" + i;
        }));
        log.info("end");
        return stringMono;
    }

Spring Data Reavtive Repositories

目前支持的响应式数据库有 Mongo,Cassandra,Redis,Couchbase,R2dbc ,目前r2dbc支持以下数据库
在这里插入图片描述

R2DBC

接下来讲述,WebFlux 如何集成R2DBC Mysql

依赖配置
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-r2dbc</artifactId>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
		</dependency>
		<!--r2dbc mysql 库-->
		<dependency>
			<groupId>dev.miku</groupId>
			<artifactId>r2dbc-mysql</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-webflux</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>io.projectreactor</groupId>
			<artifactId>reactor-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>
数据库配置
spring:
  r2dbc:
    url: r2dbc:mysql://127.0.0.1:3306/webflux?characterEncoding=utf-8&useSSL=false
    username: root
    password: root
  application:
    name: webflux

接着就可以正常像mvc一样开发了

示例项目

webflux+curd+r2dbc完整示例

https://gitee.com/chenzhehome/webflux-r2dbc-curd.git

总结

当一个网络请求到容器时,容器会为每一个请求分配线程去处理,线程会调用对应的servlet处理,当使用同步servlet时,业务逻辑的用了多久,servlet线程就要等待多久,而异步servlet是不需要等待的.他可以同时处理多个.只不过当业务逻辑完成时通过发布订阅的关系返回给他.

mvc和wedflux没有好坏之分,只不过webflux更适合处理高并发的场景,但webflux的异常排查,暂时没有太好的办法,如果不是高并发场景个人觉得还是mvc好一点.

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值