51. Desarrolle Spring WebFlux basado en anotaciones para generar datos de contrapresión, lo que significa enviar siempre mensajes al cliente.

★ Dos métodos de desarrollo de Spring WebFlux

1. 采用类似于Spring MVC的注解的方式来开发。
   此时开发时感觉Spring MVC差异不大,但底层依然是反应式API。

2. 使用函数式编程来开发

★ Desarrollar Spring WebFlux basado en anotaciones

开发上变化并不大,主要是处理方法的返回值可使用Mono或Flux,但并不强制使用Mono或Flux

WebFlux的变化主要是两点:
- 彻底抛弃Servlet API;
- 基于订阅-发布的异步机制。

这两点的区别主要体现在底层服务器能以较小的线程池处理更高的并发,从而提高应用的可伸缩性 

WebFlux支持基于背压(back press)的反应式流。

Qué es la contrapresión:
este es el concepto de reactiva: cuando la capacidad de consumo del suscriptor es mucho menor que la del editor, el suscriptor (es decir, el consumidor) tiene un mecanismo para notificar al editor que cancele o finalice la producción de datos. Este mecanismo se puede llamar "contrapresión".

Para decirlo sin rodeos, cuando los consumidores tienen un retraso en el consumo, le dicen al productor que empuja a la inversa: "Ya no necesito que produzcas más, por favor, reduce la velocidad", lo que se llama contrapresión.

Por ejemplo, este método .onBackpressionDrop() se utiliza para habilitar la función de procesamiento de contrapresión para el método. El mecanismo es que cuando el editor envía demasiados mensajes a los suscriptores y los suscriptores no pueden manejarlos, algunos datos se eliminarán para garantizar que el programa no fallará.

Demostración de código:

Utilice spring webFlux para demostrar una función de contrapresión que springmvc no puede realizar, es decir, el editor de mensajes puede enviar mensajes continuamente a los suscriptores de mensajes. Simplemente siga enviando mensajes al cliente.

Requisitos: enviar mensajes al cliente cada 5 segundos.

Al crear el proyecto, anteriormente verifiqué Spring Web, que se basa en Spring MVC, ahora quiero verificar Spring Reactive Web, que se basa en reactividad.
Insertar descripción de la imagen aquí
Como se muestra en la figura:
se puede ver que Spring WebFlux está integrado con el marco Reactor/basado en el marco Reactor.
Spring WebFlux y Reactor usan Netty como servidor web de forma predeterminada.
Spring MVC usa Tomcat como servidor web.
Insertar descripción de la imagen aquí

Simplemente escriba un proceso para consultar libros por identificación y la base de datos se reemplazará por una colección de mapas:
Insertar descripción de la imagen aquí

Escriba un método para agregar libros, tipo de envío postMapping y pruébelo con cartero.
Insertar descripción de la imagen aquí
Escriba aquí los datos del objeto de un libro y envíelo en formato json.
El backend utiliza el objeto modificado con la anotación @RequestBody para recibir los datos.
libro público addBook(@RequestBody libro libro){}
Insertar descripción de la imagen aquí

El caso es que este método, que refleja contrapresión, consiste en enviar datos al cliente todo el tiempo.

Simplifique el código:
Insertar descripción de la imagen aquí

Algunas notas:
Insertar descripción de la imagen aquí
el siguiente código para ver todos los libros.
Insertar descripción de la imagen aquí

Implementación de funciones:

Requisitos: enviar mensajes al cliente cada 5 segundos.

Cuando el proyecto se está ejecutando, inserte un dato del libro, se puede ver que la consulta se ejecuta cada 5 segundos y luego los datos se envían al cliente.

Esta es la función de contrapresión que Spring MVC no puede lograr.
Insertar descripción de la imagen aquí

Si cambia el proyecto a spring mvc, Flux no estará disponible.

    通过依赖把 <artifactId>spring-boot-starter-webflux</artifactId>
     改成  <artifactId>spring-boot-starter-web</artifactId>
     就是把 spring webflux 改成 spring mvc 框架

Insertar descripción de la imagen aquí

código completo

dependencias de pom:

        <!-- 表明使用 WebFlux , 此时是反应式 Web 应用,默认使用 Reactor netty 作为服务器 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>

Insertar descripción de la imagen aquí

dominio

package cn.ljh.my_annotation_flux.domain;
import lombok.Data;
@Data
public class Book
{
    
    
    private Integer id;
    private String name;
    private double price;
    private String author;
    
    public Book(Integer id, String name, double price, String author)
    {
    
    
        this.id = id;
        this.name = name;
        this.price = price;
        this.author = author;
    }
}

Controlador de libro

package cn.ljh.my_annotation_flux.controller;


import cn.ljh.my_annotation_flux.domain.Book;
import cn.ljh.my_annotation_flux.service.BookService;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;

import java.time.Duration;
import java.util.Collection;

@RestController
@RequestMapping("/books")
public class BookController
{
    
    
    private BookService bookService;
    //有参构造器完成依赖注入
    public BookController(BookService bookService)
    {
    
    
        this.bookService = bookService;
    }

    @GetMapping("/{id}")
    public Book viewBooks(@PathVariable Integer id)
    {
    
    
        Book book = bookService.getBook(id);
        return book;
    }



    //restful的方式提交请求 ,
    // @RequestBody主要用来接收前端传递给后端的json字符串中的数据的(请求体中的数据的);
    @PostMapping("/addBook")
    public Book addBook(@RequestBody Book book)
    {
    
    
        bookService.addBook(book);
        return book;
    }

    //    开发基于 背压的 WebFlux 反应式流,来看 spring mvc 做不到的事
    //    WebFlux支持基于背压(back press)的反应式流。
    //    背压:很多种处理方式,消息的发布者可以不断的向消息的订阅者推送消息。消息过多后的一些处理方式。


        //这个获取图书的方法,使用到了背压的技术,相当于是一个数据流、消息发布者,会不断的向客户端生成数据,
        // 因此需要指定响应的数据类型: 数据是stream数据流,数据流里面的数据格式是json
    @GetMapping(value = "/viewBooks",produces = "application/stream+json")
    //需要直接用 Reactor 特性的时候,可以让处理方法返回 Mono 或 Flux
    public Flux<Book> viewBooks()
    {
    
    
        Flux<Collection<Book>> map =

                //周期性的向客户端推送数据,每隔5秒推送一次,  interval:间隔 , Duration:持续 ,  Seconds:秒
                //Flux.interval(Duration.ofSeconds(5)) 属于上游发送消息的发送者
                Flux.interval(Duration.ofSeconds(5))
                        //onBackpressureDrop作用:实现处理背压的功能
                        .onBackpressureDrop()
                        .map((i) -> bookService.getAllBooks());

        //将 Collection 转换 Flux (相当于把同步数据集 转换成 反应式的数据发布者)。
        //flatMapIterable 方法中的Lambda 表达式负责将 Coollection 中的元素转成 Flux 中的元素。
        Flux<Book> bookFlux = map.flatMapIterable(book -> book);

        return bookFlux;
    }


}

Servicio de libros

package cn.ljh.my_annotation_flux.service;


import cn.ljh.my_annotation_flux.domain.Book;
import java.util.Collection;

public interface BookService
{
    
    
    Book getBook(Integer id);

    Integer addBook(Book book);

    Collection<Book> getAllBooks();
}

LibroServicioImpl

package cn.ljh.my_annotation_flux.service.impl;


import cn.ljh.my_annotation_flux.domain.Book;
import cn.ljh.my_annotation_flux.service.BookService;
import org.springframework.stereotype.Service;

import java.util.*;

//添加这个@Service注解,springboot就可以自动扫描这个Service组件的实现类,然后把这个类部署成容器中的bean。
@Service
public class BookServiceImpl implements BookService
{
    
    
    //添加一个 Map 集合,假设为数据库
    public static final Map<Integer, Book> bookDB = new LinkedHashMap<>();

    //创建一个自增id
    static int nextId = 4;

    //初始化这个数据库
    static
    {
    
    
        bookDB.put(1, new Book(1, "火影忍者", 100.0, "岸本"));
        bookDB.put(2, new Book(2, "家庭教师", 110.0, "天野明"));
        bookDB.put(3, new Book(3, "七龙珠Z", 120.0, "鸟山明"));
    }


    //查看图书
    @Override
    public Book getBook(Integer id)
    {
    
    
        Book book = bookDB.get(id);
        if (book == null){
    
    
            throw new RuntimeException("没有此图书信息!");
        }
        return book;
    }

    //添加图书
    @Override
    public Integer addBook(Book book)
    {
    
    
        book.setId(nextId);
        bookDB.put(nextId,book);
        //返回id,先返回在自增。
        return nextId++;
    }

    //查看所有的图书
    @Override
    public Collection<Book> getAllBooks()
    {
    
    
        //获取集合中的所有元素
        Collection<Book> values = bookDB.values();
        return values;
    }
}

Función .onBackpressionDrop()

Check.onBackpressionDrop() La función de este método:

Insertar descripción de la imagen aquí

Insertar descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/weixin_44411039/article/details/132686709
Recomendado
Clasificación