Spring Webflux学习记录

简介: 现在Reactive在Java开发者中依然还是个雾里看花的状态,都知道不是银弹,但是也都不知道在一般的业务场景它能不能用?能用到什么程度?代价是什么?因此为了破除迷信,近距离了解这项技术,从Spring Webflux开始学习,关键心得记录如下。 ## 异步思维 首先全异步编程是Reactive的核心,虽然一直作业务产品开发,但是对多线程操作也不陌生,直观感觉上即使是全异步编程也不会有太大

现在Reactive在Java开发者中依然还是个雾里看花的状态,都知道不是银弹,但是也都不知道在一般的业务场景它能不能用?能用到什么程度?代价是什么?因此为了破除迷信,近距离了解这项技术,从Spring Webflux开始学习,关键心得记录如下。

异步思维

首先全异步编程是Reactive的核心,虽然一直作业务产品开发,但是对多线程操作也不陌生,直观感觉上即使是全异步编程也不会有太大的不适应。但是,全异步真的是需要另一套代码习惯。

下面这段代码,按照我一开始的理解应该是要输出都能输出,但是事实上直接就报了“java.io.IOException: Pipe closed”,也就是说由于使用了JDK8 Closeable方式的try catch写法,导致在实际写入前就在主线程被关闭。

在这里传统的优雅的写法成为了全异步化编程模型的“陋习”,不得不在onFinally或者后续的阻塞场景写一些样板代码将其close。同时这里也暴露了另一个问题,那就是在传统开发模式和Reactive混合使用时,很容易由于前置的同步代码潜在的预期语义,导致异步化后出现各种难以捉摸的异常,并且如果没写doOnError还会丢失异常信息。

@RestController
@RequestMapping("/test")
public class GreetingHandler {

    @GetMapping("/hello")
    public Flux<String> hello(ServerHttpRequest request) {
        return Flux.just("a", "b", "c");
    }
}

public static void main(String[] args) throws Exception {
    String url = "http://localhost:8080/test/hello";
    Flux<DataBuffer> response = WebClient.create()
        .get().uri(url).exchange()
        .flatMapMany(b -> b.bodyToFlux(DataBuffer.class));

    try(PipedOutputStream outputStream = new PipedOutputStream();
        PipedInputStream inputStream = new PipedInputStream(outputStream)) {
        DataBufferUtils.write(response, outputStream)
            .doFinally(s -> {
                System.out.println("doFinally: " + s.toString() + Thread.currentThread().getId());
                try {
                    System.out.println(inputStream.available());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            })
            .doOnNext(dataBuffer -> {
                System.out.println("doOnNext" + Thread.currentThread().getId());
            })
            .doOnError(t -> {
                logger.error("", t);
            })
            .subscribe(DataBufferUtils.releaseConsumer());
    } catch (Exception e) {
        logger.error("", e);
    }
}

客户端限制

Webflux将Controller的返回固定成另Mono和Flux两种,通过使用浏览器接收到的和普通接口无二,那Webflux真的不限制客户端类型吗?

了解这个问题最好的办法一是看源码,其次就是抓包看一下通信协议。本次使用Wireshark抓包,截图如下。从服务端返回可以看出发送了三次数据,因此说明FLux接口会分成多个chunk返回客户端,同时整体上还是一个完整的HTTP协议,所以客户端不受服务端选型影响。
20200627160501.jpg

小结

从目前的初步了解来看,在一般的业务中实战Reactive就是个高风险的选型,因为有性能压力的往往只会是少数几个接口,而开发模型混合之后维护难度会加大不少,这或许就是节约成本的代价。

相关文章
|
2月前
|
前端开发 Java 开发者
Spring生态学习路径与源码深度探讨
【11月更文挑战第13天】Spring框架作为Java企业级开发中的核心框架,其丰富的生态系统和强大的功能吸引了无数开发者的关注。学习Spring生态不仅仅是掌握Spring Framework本身,更需要深入理解其周边组件和工具,以及源码的底层实现逻辑。本文将从Spring生态的学习路径入手,详细探讨如何系统地学习Spring,并深入解析各个重点的底层实现逻辑。
75 9
|
3月前
|
前端开发 Java 数据库
SpringBoot学习
【10月更文挑战第7天】Spring学习
46 9
|
2月前
|
Java Kotlin 索引
学习Spring框架特性及jiar包下载
Spring 5作为最新版本,更新了JDK基线至8,修订了核心框架,增强了反射和接口功能,支持响应式编程及Kotlin语言,引入了函数式Web框架,并提升了测试功能。Spring框架可在其官网下载,包括文档、jar包和XML Schema文档,适用于Java SE和Java EE项目。
38 0
|
3月前
|
XML Java 数据格式
Spring学习
【10月更文挑战第6天】Spring学习
31 1
|
3月前
|
Java 测试技术 开发者
springboot学习四:Spring Boot profile多环境配置、devtools热部署
这篇文章主要介绍了如何在Spring Boot中进行多环境配置以及如何整合DevTools实现热部署,以提高开发效率。
120 2
|
3月前
|
前端开发 Java 程序员
springboot 学习十五:Spring Boot 优雅的集成Swagger2、Knife4j
这篇文章是关于如何在Spring Boot项目中集成Swagger2和Knife4j来生成和美化API接口文档的详细教程。
345 1
|
3月前
|
Java API Spring
springboot学习七:Spring Boot2.x 拦截器基础入门&实战项目场景实现
这篇文章是关于Spring Boot 2.x中拦截器的入门教程和实战项目场景实现的详细指南。
44 0
springboot学习七:Spring Boot2.x 拦截器基础入门&实战项目场景实现
|
3月前
|
Java API Spring
springboot学习六:Spring Boot2.x 过滤器基础入门&实战项目场景实现
这篇文章是关于Spring Boot 2.x中过滤器的基础知识和实战项目应用的教程。
51 0
springboot学习六:Spring Boot2.x 过滤器基础入门&实战项目场景实现
|
3月前
|
Java 关系型数据库 MySQL
springboot学习五:springboot整合Mybatis 连接 mysql数据库
这篇文章是关于如何使用Spring Boot整合MyBatis来连接MySQL数据库,并进行基本的增删改查操作的教程。
404 0
springboot学习五:springboot整合Mybatis 连接 mysql数据库
|
3月前
|
Java 关系型数据库 MySQL
springboot学习四:springboot链接mysql数据库,使用JdbcTemplate 操作mysql
这篇文章是关于如何使用Spring Boot框架通过JdbcTemplate操作MySQL数据库的教程。
147 0
springboot学习四:springboot链接mysql数据库,使用JdbcTemplate 操作mysql