【从零开始学Spring Boot】-14.Spring Boot WebFlux初体验


1.简介

1.1 概述

Spring WebFlux is the new reactive web framework introduced in Spring Framework 5.0. Unlike Spring MVC, it does not require the Servlet API, is fully asynchronous and non-blocking, and implements the Reactive Streams specification through the Reactor project.

Spring WebFlux comes in two flavors: functional and annotation-based. The annotation-based one is quite close to the Spring MVC model, as shown in the following example:

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

1.2 特点

Reactive Streams plays an important role for interoperability. It is of interest to libraries and infrastructure components but less useful as an application API, because it is too low-level. Applications need a higher-level and richer, functional API to compose async logic — similar to the Java 8 Stream API but not only for collections. This is the role that reactive libraries play.

Reactor is the reactive library of choice for Spring WebFlux. It provides the Mono and Flux API types to work on data sequences of 0..1 (Mono) and 0..N (Flux) through a rich set of operators aligned with the ReactiveX vocabulary of operators. Reactor is a Reactive Streams library and, therefore, all of its operators support non-blocking back pressure. Reactor has a strong focus on server-side Java. It is developed in close collaboration with Spring.

WebFlux requires Reactor as a core dependency but it is interoperable with other reactive libraries via Reactive Streams. As a general rule, a WebFlux API accepts a plain Publisher as input, adapts it to a Reactor type internally, uses that, and returns either a Flux or a Mono as output. So, you can pass any Publisher as input and you can apply operations on the output, but you need to adapt the output for use with another reactive library. Whenever feasible (for example, annotated controllers), WebFlux adapts transparently to the use of RxJava or another reactive library. See Reactive Libraries for more details.

响应流对于互操作性起着重要作用。库和基础结构组件对此很感兴趣,但由于它太底层了,它作为应用程序API的用处不大。应用程序需要更高级别且功能更丰富的API来构成异步逻辑,这与Java 8 Stream API相似,但不仅适用于集合。这就是反应式库的作用。

Reactor是Spring WebFlux的首选反应库。它提供了Mono和Flux API类型,以通过与ReactiveX运算符词汇对齐的一组丰富的运算符来处理 0..1 (Mono) 和 0..N (Flux) 的数据序列。 Reactor是Reactive Streams库,因此,它的所有运算符都支持无阻塞背压。 Reactor非常注重服务器端Java。它是与Spring紧密合作开发的。

WebFlux需要Reactor作为核心依赖项,但是它可以通过Reactive Streams与其他React库进行互操作。通常,WebFlux API接受普通的发布者作为输入,在内部将其适应于Reactor类型,使用该类型,然后返回 FluxMono 作为输出。因此,您可以将任何发布服务器作为输入传递,并且可以对输出应用操作,但是您需要调整输出以与其他反应式库一起使用。只要可行(例如,带注释的控制器),WebFlux就会透明地适应RxJava或其他反应式库的使用。有关更多详细信息,请参见反应式库。

1.3 对比

2.演示环境

  1. JDK 1.8.0_201
  2. Spring Boot 2.2.0.RELEASE
  3. 构建工具(apache maven 3.6.3)
  4. 开发工具(IntelliJ IDEA )

3.演示代码

3.1 代码说明

通过 @RestController 类似 Spring Mvc 的方式演示 Spring WebFlux 的使用

3.2 代码结构

3.3 maven 依赖

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

3.4 配置文件

无内容

3.5 java代码

UserModel.java

public class UserModel {
    private Long id;
    private String name;
    private Integer age;
    private String birthday;
    private String address;
    private String phone;

    public UserModel() {}

    public UserModel(Long id, String name, Integer age, String birthday, String address, String phone) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.birthday = birthday;
        this.address = address;
        this.phone = phone;
    }

    // get&set&toString
}

UserRepository.java

@Repository
public class UserRepository {

    // 预置两条数据,所以起始值从2开始
    private static final AtomicLong ID_GENERATOR = new AtomicLong(2);

    // 模拟数据库操作
    private static final Map<Long, UserModel> USER_MAP = new HashMap<>();

    @PostConstruct
    public void init() {
        UserModel user1 = new UserModel(1L, "zhangsan", 20, "2000-01-02", "beijing", "13666666666");
        UserModel user2 = new UserModel(2L, "lisi", 30, "1990-03-23", "shanghai", "13888888888");
        USER_MAP.put(user1.getId(), user1);
        USER_MAP.put(user2.getId(), user2);
    }

    public List<UserModel> findAll() {
        return new ArrayList<>(USER_MAP.values());
    }

    public UserModel findById(Long id) {
        return USER_MAP.get(id);
    }

    public UserModel add(UserModel userModel) {
        long id = ID_GENERATOR.incrementAndGet();
        userModel.setId(id);
        USER_MAP.put(id, userModel);
        return userModel;
    }

    public UserModel update(UserModel userModel) {
        USER_MAP.put(userModel.getId(), userModel);
        return USER_MAP.get(userModel.getId());
    }

    public UserModel deleteById(Long id) {
        UserModel userModel = USER_MAP.get(id);
        USER_MAP.remove(id);
        return userModel;
    }
}

UserController.java

@RestController
@RequestMapping(value = "/user")
public class UserController {

    @Autowired
    private UserRepository userRepository;

    @GetMapping(value = "/list")
    public Flux<UserModel> list() {
        return Flux.fromStream(userRepository.findAll().stream());
    }

    @GetMapping(value = "/find/{id}")
    public Mono<UserModel> findById(@PathVariable Long id) {
        return Mono.just(userRepository.findById(id));
    }

    @PostMapping(value = "/add")
    public Mono<UserModel> add(@RequestBody UserModel userModel) {
        return Mono.just(userRepository.add(userModel));
    }

    @PutMapping(value = "/update")
    public Mono<UserModel> update(@RequestBody UserModel userModel) {
        return Mono.just(userRepository.update(userModel));
    }

    @DeleteMapping(value = "/delete/{id}")
    public Mono<UserModel> deleteById(@PathVariable Long id) {
        return Mono.just(userRepository.deleteById(id));
    }
}

3.6 git 地址

spring-boot/spring-boot-07-webflux/spring-boot-webflux-demo

4.效果展示

启动 SpringBootWebfluxDemoApplication.main 方法,在 spring-boot-webflux-demo.http 访问下列地址,观察输出信息是否符合预期。

查询用户列表

### GET /user/list
GET http://localhost:8080/user/list
Accept: application/json

根据id查询用户

### GET /user/find/{id}
GET http://localhost:8080/user/find/1
Accept: application/json

新增用户

### POST /user/add
POST http://localhost:8080/user/add
Accept: application/json
Content-Type: application/json

{
  "name": "wangwu",
  "age": 25,
  "birthday": "1995-06-23",
  "address": "guangzhou",
  "phone": "13777777777"
}

修改用户

### PUT /user/update
PUT http://localhost:8080/user/update
Accept: application/json
Content-Type: application/json

{
  "id": 2,
  "name": "lisi2",
  "age": 32,
  "birthday": "1988-03-23",
  "address": "shanghai2",
  "phone": "13888888882"
}

根据id删除用户

### DELETE /user/delete/{id}
DELETE http://localhost:8080/user/delete/3
Accept: application/json

5.参考

  1. Spring-Boot-Features/WebFlux
  2. Spring Framework/WebFlux

文章作者: Soulballad
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Soulballad !
评论
 上一篇
【源码分析-Spring Boot】-13.Spring Boot WebFlux 工作流程及原理 【源码分析-Spring Boot】-13.Spring Boot WebFlux 工作流程及原理
Spring Boot WebFlux:【从零开始学Spring Boot】-14.Spring Boot WebFlux初体验 1.Spring WebFlux 运行流程在 Spring Mvc 中处理核心类是 Dispatcher
2020-07-28
下一篇 
【从零开始学Spring Boot】-13.Spring Boot Jpa多数据源 【从零开始学Spring Boot】-13.Spring Boot Jpa多数据源
1.简介1.1 概述在实际项目中一般是一个数据源,但是在某些特殊场景可能需要多个数据源,这里以 spring boot jpa 为例演示一下多数据源的配置和使用。 2.演示环境 JDK 1.8.0_201 Spring Boot 2.2.0
  目录