Spring Boot WebFlux (学习笔记-1 2021.03.26)

前言: (SpringWebFlux官网) (Reactive官网)

Spring MVC Web架构是基于阻塞式Servlet API构建的。Servlet 3.1后提供了非阻塞API

Spring WebFluxSpring Framework 5.0中引入的新的响应式Web框架。与Spring MVC不同,它不需要Servlet API,是完全异步且无阻塞的,并通过Reactor项目实现Reactive Streams规范, Spring WebFlux有两种形式:功能性的和基于注释的。基于注释的模型非常类似于Spring MVC模型;

Spring Boot 2.0 以后版本才是基于Spring Framework 5.0 进行构建的, 如果需要使用Spring WebFlux 版本必须大于2.0

其优势在与:

Spring WebFlux 是一个异步非阻塞式的 Web 框架,它能够充分利用多核 CPU 的硬件资源去处理大量的并发请求。

WebFlux 并不能使接口的响应时间缩短,它仅仅能够提升吞吐量和伸缩性

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ku3CePLa-1616768287147)(https://docs.spring.io/spring-framework/docs/5.3.1/reference/html/images/spring-mvc-and-webflux-venn.png)]

从图可以看到Spring WebFlux是非阻塞式的, 同样支持@Controller注解, 在Netty,Undertow和Servlet 3.1+容器等服务器上运行, 支持 Reactive Streams,并其目前只支持非关系型数据库,如Mongo,Redis等。

Spring MVC 能满足场景的,就不需要更改为 Spring WebFlux

要注意容器的支持,可以看看底层 内嵌容器 的支持。

微服务 体系结构,Spring WebFluxSpring MVC 可以混合使用。尤其开发 IO 密集型 服务的时候,可以选择 Spring WebFlux 去实现。

下面进行快速入门学习

1.0 项目基于SpringBoot 2.2.0版本

1.1.1 引入依赖webflux 替换web依赖

<artifactId>spring-boot-starter-web</artifactId>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

Reactor 是Spring WebFlux所使用的响应式库,其提供了两个特殊的类MonoFlux

Mono和Flux在发布订阅模式中都属于发布者(不清楚的可以参考Java 9 Flow API学习),查看源码会发现它们都实现了Publisher接口。

Mono表示0 ~ 1个元素的数据发布者,Flux表示 0 ~ N个元素的数据发布者。我们可以通过一个例子来了解Mono和Flux

	@Test
    public void contextLoads() {
        Integer i = 88;
        // Mono发布者发布一个数据
        Mono.fromSupplier(() -> i + 12)
                // 消费发布数据
                .subscribe(integer -> System.out.println(integer));

        // Flux发布者发布多个数据
        Integer[] arr = {88, 22};
        Flux.fromArray(arr)
                .map(integer -> integer + 1)
                // 消费发布数据
                .subscribe(integer -> 
                    System.out.println(integer)
                );
    }

1.1.2 返回值MonoController控制层用法

@RestController
@RequestMapping("/web")
public class WebFluxController {

    @Autowired
    private SleepService sleepService;  //此service 方法只是 TimeUnit.SECONDS.sleep(2); 睡眠2秒, 然后返回字符串

    @GetMapping("/test1")
    public String test1(){
        long start = System.currentTimeMillis();
        System.out.println("test1开始执行");
        String sleep = sleepService.sleep("困");
        long end = System.currentTimeMillis() - start;
        String str = "test1耗时:" + end + "毫秒, 原因" + sleep;
        System.out.println(str);
        return str;
    }

    @GetMapping("/test2")
    public Mono<String> test2(){
        long start = System.currentTimeMillis();
        System.out.println("test2开始执行");
        Mono<String> mono = Mono.fromSupplier(() -> sleepService.sleep("困"));
        long end = System.currentTimeMillis() - start;
        System.out.println("test2耗时:"+end+"毫秒, 原因"+mono.block());
        return mono;
    }
    
    @GetMapping("/test3")
    public Mono<String> test3() {
        System.out.println("test3开始执行");
        logger.info("线程名称:{}",Thread.currentThread().getName());
        String sleep = sleepService.sleep("困");
        return Mono.just(sleep);
    }
}

进行访问后的控制台结果:

test1开始执行
test1耗时:2001毫秒, 原因困睡觉结束
test2开始执行
test2耗时:6毫秒, 原因困睡觉结束

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cyixAQFF-1616768287149)(https://s3.ax1x.com/2020/12/10/rigDFe.png)]

可以看到test2方法里的Mono<String> mono = Mono.fromSupplier(() -> sleepService.sleep("困"))是异步非阻塞的,不用等待service业务执行完成, 就能继续往下执行, 但是注意并不能加快响应速度, 通常使用的是Mono.just(sleep) , 并且浏览器返回的也是service返回的字符串

1.1.3 返回值 FluxController控制层用法

	@GetMapping(value = "/test4",produces = MediaType.APPLICATION_JSON_VALUE)
    public Flux<String> test4() {
        long start = System.currentTimeMillis();
        System.out.println("test4开始执行");
        Flux<String> fromArray = Flux.fromStream(
                () -> Stream.of(sleepService.sleep("kun"),"另一个方法")
        );
        long end = System.currentTimeMillis() - start;
        System.out.println("test4耗时:" + end + "毫秒");
        return fromArray;
    }

 	@GetMapping("/test5")
    public Mono<String> test5() {
        System.out.println("test5开始执行");
        logger.info("线程名称:{}",Thread.currentThread().getName());
        String sleep = sleepService.sleep("困");
        return Flux.just(sleep);
    }

扩展:

Mono,Flux常用方法

Flux

可以通过Flux类的静态方法来生成:

  1. just():可以指定序列中包含的全部元素。创建出来的 Flux 序列在发布这些元素之后会自动结束。
  2. fromArray()fromIterable()fromStream():可以从一个数组、Iterable 对象或 Stream 对象中创建 Flux 对象。
  3. empty():创建一个不包含任何元素,只发布结束消息的序列。
  4. error(Throwable error):创建一个只包含错误消息的序列。
  5. never():创建一个不包含任何消息通知的序列。
  6. range(int start, int count):创建包含从 start 起始的 count 个数量的 Integer 对象的序列。
  7. interval(Duration period)interval(Duration delay, Duration period):创建一个包含了从 0 开始递增的 Long 对象的序列。其中包含的元素按照指定的间隔来发布。除了间隔时间之外,还可以指定起始元素发布之前的延迟时间。

Mono

Mono 的创建方式与之前介绍的 Flux 比较相似。Mono 类中也包含了一些与 Flux 类中相同的静态方法。这些方法包括 just(),empty(),error()和 never()等。除了这些方法之外,Mono 还有一些独有的静态方法:

  1. fromCallable()fromCompletionStage()fromFuture()fromRunnable()和 fromSupplier():分别从 Callable、CompletionStage、CompletableFuture、Runnable 和 Supplier 中创建 Mono。
  2. delay(Duration duration):创建一个 Mono 序列,在指定的延迟时间之后,产生数字 0 作为唯一值。
  3. ignoreElements(Publisher<T> source):创建一个 Mono 序列,忽略作为源的 Publisher 中的所有元素,只产生结束消息。
  4. justOrEmpty(Optional<? extends T> data)justOrEmpty(T data):从一个 Optional 对象或可能为 null 的对象中创建 Mono。只有 Optional 对象中包含值或对象不为 null 时,Mono 序列才产生对应的元素。

1

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐