Spring5.0响应式编程入门

引言
? 响应式编程是一种面向数据流和变化传播的编程范式。使用它可以在编程语言中很方便地表达静态或动态的数据流,而相关的计算模型会自动将变化的值通过数据流进行传播。我们可以使用声明的方式构建应用程序的能力,形成更加敏感和有弹性的应用,所以Spring 5在其核心框架中增加了反应系统,已经开始向声明式编程的范式转变。

响应式编程的优势

  • 提高了代码的可读性,因此开发人员只需要关注定义业务逻辑。
  • 在高并发环境中,可以自然的处理消息。
  • 可以控制生产者和消费者之间的流量,避免内存不足。
  • 对于一个或多个线程,IO绑定任务可以通过异步和非阻塞方式执行,而且不阻塞当前线程。
  • 可以有效的管理多个连接系统之间的通信。

应用场景

  • 大量的交易处理服务,如银行部门。
  • 大型在线购物应用程序的通知服务,如亚马逊。
  • 股票价格同时变动的股票交易业务。

Spring 5.0前瞻
作为Java中的首个响应式Web框架,Spring 5.0最大的亮点莫过于提供了完整的端到端响应式编程的支持。

如上图所示左侧是传统的基于Servlet的Spring Web MVC框架,右侧是spring 5.0新引入的基于Reactive Streams的Spring WebFlux框架,从上往下依次是:Router Functions,WebFlux,Reactive Streams三个新组件,其中:

  • Router Functions: 对标@Controller,@RequestMapping等标准的Spring MVC注解,提供一套函数式风格的API,用于创建Router,Handler和Filter。
  • WebFlux: 核心组件,协调上下游各个组件提供响应式编程支持。
  • Reactive Streams: 一种支持背压(Backpressure)的异步数据流处理标准,主流实现有RxJava和Reactor,Spring WebFlux默认集成的是Reactor。

示例代码
1.创建项目
spring响应式开发,需要结合spring boot来完成,所以使用idea创建springboot项目,选择Spring Initializr选项,jdk选择1.8以上。

选择下一步,设置groupId和artifactId。

选择下一步,选择web选项中的Reactive web选项,表明要创建响应式项目,注意Spring Boot的版本为2.0.2。

选择下一步,设置项目的目录,点击finish创建项目。

2.设置服务端口
为了避免端口冲突,我们可以在项目的application.properties文件中配置服务端口。

server.port=9002
3.相关依赖包
打开项目的pom.xml文件,会发现以下几个依赖包

<dependencies>
    <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>
    </dependency>
    <dependency>
        <groupId>io.projectreactor</groupId>
        <artifactId>reactor-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

其中:

  • spring-boot-starter-webflux:webflux依赖包,是响应式开发的核心依赖包,其中包含了spring-boot-starter-reactor-netty 、spring 5 webflux 包,默认是通过netty启动的。
  • spring-boot-starter-test:springboot的单元测试工具库。
  • reactor-test:Spring 5提供的官方针对RP框架测试工具库。

小结
? spring响应式开发需要结合spring boot来完成,同时需要引入spring-boot-starter-webflux和reactor-test两个依赖包来支持响应式开发。

4.使用webflux创建web应用
webflux的使用有两种方式,基于注解和函数式编程。这里使用函数式编程,具体操作如下:

4.1.创建实体类

public class Good {
?
    private int id;
    private String name;
    private String price;
?
    public Good(int id,String name,String price){
        this.id=id;
        this.name=name;
        this.price=price;
    }
?
    public int getId() {
        return id;
    }
?
    public void setId(int id) {
        this.id = id;
    }
?
    public String getName() {
        return name;
    }
?
    public void setName(String name) {
        this.name = name;
    }
?
    public String getPrice() {
        return price;
    }
?
    public void setPrice(String price) {
        this.price = price;
    }
?
    @Override
    public String toString() {
        return "Good{" +
                "id=" + id +
                ", name=‘" + name + ‘\‘‘ +
                ", price=‘" + price + ‘\‘‘ +
                ‘}‘;
    }
}

分析: 实体类没有什么特殊的操作,原来怎么操作现在还是怎么操作。

4.2.创建GoodGenerator

@Configuration
public class GoodGenerator {
?
    public Flux<Good> findGoods(){
        List<Good> goods = new ArrayList<>();
        goods.add(new Good(1,"小米","2000"));
        goods.add(new Good(2,"华为","4000"));
        goods.add(new Good(3,"苹果","8000"));
        return Flux.fromIterable(goods);
    }
}

分析: 这里的方法返回的是Flux类型的数据,Flux是RP中最基础的数据类型之一,对应的是多值数据的返回操作,在RP中还有Mono数据类型,也是最基础的数据类型之一,对应单值数据的返回操作。

注意:这里的GoodGenerator类要加上@Configuration注解。

4.3.创建GoodHandler

@Component
@Configuration
public class GoodHandler {
?
    private final Flux<Good> goods;
?
    public GoodHandler(GoodGenerator goodGenerator) {
        this.goods = goodGenerator.findGoods();
    }
?
    public Mono<ServerResponse> hello(ServerRequest request) {
?
        return ok().contentType(TEXT_PLAIN)
                .body(BodyInserters.fromObject("Hello Spring!"));
    }
?
    public Mono<ServerResponse> echo(ServerRequest request) {
        return ok().contentType(APPLICATION_STREAM_JSON)
                .body(this.goods,Good.class);
    }
}

分析: Handler主要用来处理请求操作,并将Mono<ServerResponse>返回,Mono<ServerResponse>中会封装响应数据,响应数据如果是字符串可以使用:


ok().contentType(TEXT_PLAIN).body(BodyInserters.fromObject("Hello Spring!"));

操作,如果是集合数据可以使用:


ok().contentType(APPLICATION_STREAM_JSON).body(this.goods,Good.class)

操作。

4.4.创建GoodRouter


@Configuration
public class GoodRouter {
    @Bean
    public RouterFunction<ServerResponse> route(GoodHandler goodHandler) {
?
      return RouterFunctions
              .route(RequestPredicates.GET("/good")
                      .and(RequestPredicates.accept(MediaType.TEXT_PLAIN)),goodHandler::hello)
              .andRoute(RequestPredicates.GET("/goods")
                      .and(RequestPredicates.accept(MediaType.APPLICATION_STREAM_JSON)),goodHandler::echo);
    }
?
}

分析: GoodRouter主要用来设置请求路径和转化HTTP请求,可以使用route()方法和andRoute方法设置多个请求路径和转化操作。

小结
? HTTP请求会由GoodRouter转发给对应的Handler,Handler处理请求,并返回Mono<ServerResponse>,这里的Router类似@RequestMapping,Handler类似Controller

4.4.运行测试
? 实体类、GoodGenerator、GoodHandler、GoodRouter都已经创建完成了,我们可以运行项目打开浏览器进行测试.

浏览器输入http://localhost:9002/good,即可获取到"Hello Spring!"文本信息

浏览器输入http://localhost:9002/goods,即可获取到集合信息


到目前为止,一个简单的webflux示例已经完成。

4.5.单元测试
在项目中我们也可以使用使用一个Spring 5新引入的测试工具类,WebTestClient,专门用于测试RP应用,具体代码如下:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class Spring5demoApplicationTests {
?
    @Autowired
    private WebTestClient webTestClient;
?
    @Test
    public void helloTest() {
      String s=  webTestClient
                .get().uri("/good")
                .accept(MediaType.TEXT_PLAIN).exchange()
                .expectStatus().isOk().returnResult(String.class)
                .getResponseBody().blockFirst();
?
        System.out.println(s);
    }
?
    @Test
    public void findGoodsTest(){
        webTestClient.get().uri("/goods")
                .accept(MediaType.APPLICATION_STREAM_JSON)
                .exchange().expectStatus().isOk()
                .expectHeader().contentType(MediaType.APPLICATION_STREAM_JSON)
                .returnResult(Good.class)
                .getResponseBody().collectList();
    }
}

创建WebTestClient实例时可以看到,编写RP应用的单元测试,同样也是数据不落地的流式风格

总结
? 到此,spring 5.0的响应式编程就给大家介绍到这里,这里只是简单进行了一个响应式入门操作,但是也能够体现出响应式编程的特点。当然spring 5.0响应式编程也不是完美的,它在故障诊断、依赖库集成、数据存储以及Spring Security安全权限框架支持等方面还是有局限性的。?

原文地址:http://blog.51cto.com/13587708/2130926

时间: 2024-10-20 23:23:53

Spring5.0响应式编程入门的相关文章

响应式编程系列(一):什么是响应式编程?reactor入门

响应式编程 系列文章目录 (一)什么是响应式编程?reactor入门 (二)Flux入门学习:流的概念,特性和基本操作 (三)Flux深入学习:流的高级特性和进阶用法 (四)reactor-core响应式api如何测试和调试? (五)Spring reactive: Spring WebFlux的使用 (六)Spring reactive: webClient的使用 引言 Spring framework 5 的一大新特性:响应式编程(Reactive Programming).那么什么是响应式

SpringBoot 2.x (14):WebFlux响应式编程

响应式编程生活案例: 传统形式: 一群人去餐厅吃饭,顾客1找服务员点餐,服务员把订单交给后台厨师,然后服务员等待, 当后台厨师做好饭,交给服务员,经过服务员再交给顾客1,依此类推,该服务员再招待顾客2. 服务员可以理解为服务器,服务器越多,可处理的顾客请求越多 响应式编程: 服务员记住到顾客1的要求,交给后台厨师,再记住顾客2的要求,交给后台厨师,依此类推 当厨师做好顾客1的饭,告知服务员,然后服务员把饭送到顾客1: 当厨师做好顾客2的饭,告知服务员,然后服务员把饭送到顾客2,依此类推 一系列的

1小时让你掌握响应式编程,并入门Reactor

我看同步阻塞 “你知道什么是同步阻塞吗”,当然知道了.“那你怎么看它呢”,这个... 在同步阻塞的世界里,代码执行到哪里,数据就跟到哪里.如果数据很慢跟不上来,代码就停在那里等待数据的到来,然后再带着数据一起往下执行. 可以说是,代码执行和数据是结伴而行,不离不弃.执子之手与子偕老.让人老感动了. 如果还不太理解的话,可以认为代码执行其实就是一些行为动作,这些行为动作的目的就是为了获取/操作数据. 例如加法,这里的行为动作就是执行相加,数据就是加数和被加数.操作结果就是得到了另一个数据,即两个数

Unity基于响应式编程(Reactive programming)入门

系列目录 [Unity3D基础]让物体动起来①--基于UGUI的鼠标点击移动 [Unity3D基础]让物体动起来②--UGUI鼠标点击逐帧移动 时光煮雨 Unity3D让物体动起来③—UGUI DoTween&Unity Native2D实现 时光煮雨 Unity3D实现2D人物动画① UGUI&Native2D序列帧动画 时光煮雨 Unity3D实现2D人物动画② Unity2D 动画系统&资源效率 背景 前有慕容小匹夫的一篇<解构C#游戏框架uFrame兼谈游戏架构设计&

RxJava入门系列四,Android中的响应式编程

RxJava入门系列四,Android中的响应式编程 在入门系列1,2,3中,我基本介绍了RxJava是如何使用的.但是作为一名Android开发人员,你怎么让RxJava能为你所用呢?这篇博客我将针对Android开发来介绍一下RxJava的使用场景. RxAndroid RxAndroid是为Android打造的RxJava扩展.通过RxAndroid可以让你的Android开发变得更轻松. 首先,RxAndroid中提供了AndroidSchedulers,你可以用它来切换Android线

RxJava入门系列三,响应式编程

RxJava入门系列三,响应式编程 在RxJava入门系列一,我向你介绍了RxJava的基础架构.RxJava入门系列二,我向你展示了RxJava提供的多种牛逼操作符.但是你可能仍然没能劝服自己使用RxJava,这一篇博客里我将向你展示RxJava提供的其他优势,没准了解了这些优势,你就真的想去使用RxJava了. 异常处理 直到目前为止,我都没有去介绍onComplete()和onError()方法.这两个方法是用来停止Observable继续发出事件并告知观察者为什么停止(是正常的停止还是因

RxJS入门之函数响应式编程

一.函数式编程 1.声明式(Declarativ) 和声明式相对应的编程?式叫做命令式编程(ImperativeProgramming),命令式编程也是最常见的?种编程?式. //命令式编程: function double(arr) { const results = [] for (let i = 0; i < arr.length; i++){ results.push(arr[i] * 2) } return results } function addOne(arr){ const r

Spring Boot (十四): 响应式编程以及 Spring Boot Webflux 快速入门

1. 什么是响应式编程 在计算机中,响应式编程或反应式编程(英语:Reactive programming)是一种面向数据流和变化传播的编程范式.这意味着可以在编程语言中很方便地表达静态或动态的数据流,而相关的计算模型会自动将变化的值通过数据流进行传播. 例如,在命令式编程环境中,a=b+c 表示将表达式的结果赋给 a,而之后改变 b 或 c 的值不会影响 a .但在响应式编程中,a 的值会随着 b 或 c 的更新而更新. 响应式编程是基于异步和事件驱动的非阻塞程序,只需要在程序内启动少量线程扩

响应式编程库Reactor 3 Reference Guide参考文档中文版(v3.2.0)

Project Reactor 是 Spring WebFlux 的御用响应式编程库,与 Spring 是兄弟项目. 关于如何基于Spring的组件进行响应式应用的开发,欢迎阅读系列文章<响应式Spring的道法术器>. 官方参考文档地址:http://projectreactor.io/docs/core/release/reference/中文翻译文档地址:http://htmlpreview.github.io/?https://github.com/get-set/reactor-co