spring boot 2.1学习笔记【十五】SpringBoot 2.1 WebFlux

springboot系列学习笔记全部文章请移步值博主专栏**: spring boot 2.X/spring cloud Greenwich。
由于是一系列文章,所以后面的文章可能会使用到前面文章的项目。springboot系列代码全部上传至GitHub:https://github.com/liubenlong/springboot2_demo
本系列环境:Java11;springboot 2.1.1.RELEASE;springcloud Greenwich.RELEASE;MySQL 8.0.5;

文章目录

  • Spring Boot 2 WebFlux 简介
    • Spring Boot 2.0 WebFlux 特性
    • WebFlux与WebMVC的关系
    • Spring Boot 2.0 WebFlux 组件
  • 第一个webflux程序
    • springboot webmvc 程序
    • spring boot webflux 程序
  • 使用HandlerFunction和RouterFunction实现web服务端
  • 服务器推送

Spring Boot 2 WebFlux 简介

Spring WebFlux是随Spring 5推出的响应式Web框架。Spring Boot 2.X 提供了对 WebFlux的支持。
在这里插入图片描述

Spring WebFlux是基于响应式流的,因此可以用来建立异步的、非阻塞的、事件驱动的服务。它采用Reactor作为首选的响应式流的实现库,不过也提供了对RxJava的支持。
Spring Boot 2.0 包括一个新的 spring-webflux 模块。该模块包含对响应式 HTTP 和 WebSocket 客户端的支持,以及对 REST,HTML 和 WebSocket 交互等程序的支持。一般来说,Spring MVC 用于同步处理,Spring Webflux 用于异步处理。
由于响应式编程的特性,Spring WebFlux和Reactor底层需要支持异步的运行环境,比如Netty和Undertow;也可以运行在支持异步I/O的Servlet 3.1的容器之上,比如Tomcat(8.0.23及以上)和Jetty(9.0.4及以上)。
Spring Boot Webflux 有两种编程模型实现,一种类似 Spring MVC 注解方式,另一种是使用其功能性端点方式。

Spring Boot 2.0 WebFlux 特性

常用的 Spring Boot 2.0 WebFlux 生产的特性如下:

  • 响应式 API
  • 编程模型
  • 适用性
  • 内嵌容器
  • Starter 组件

还有对日志、Web、消息、测试及扩展等支持。

WebFlux与WebMVC的关系

在这里插入图片描述

spring mvc 和 spring webflux 是有交集的,两者可以混合使用,建议IO密集型采用webflux。

Spring Boot 2.0 WebFlux 组件

Spring Boot WebFlux 官方提供了很多 Starter 组件,每个模块会有多种技术实现选型支持,来实现各种复杂的业务需求:

Web:Spring WebFlux
模板引擎:Thymeleaf
存储:Redis、MongoDB、Cassandra。不支持 MySQL
内嵌容器:Tomcat、Jetty、Undertow

第一个webflux程序

我们从springmvc转为webflux。

springboot webmvc 程序

一个最简单的程序:
引入依赖

<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-webartifactId>
dependency>

编写主程序

@SpringBootApplication
public class Application {
	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}
}

编写测试controller

@RestController
public class MyController {
    //spring mvc
    @GetMapping("/hello")
    public String hello() {
        return "Welcome to reactive world ~";
    }
}

启动,可以看到默认是Tomcat
在这里插入图片描述
访问URL
在这里插入图片描述

spring boot webflux 程序

在之前基础上,将依赖spring-boot-starter-web改为spring-boot-starter-webflux

<dependency>
   <groupId>org.springframework.bootgroupId>
   <artifactId>spring-boot-starter-webfluxartifactId>
dependency>

将controller改为

@RestController
public class MyController {
    @GetMapping("/hello")
    public Mono<String> hello1() {
        return Mono.just("Welcome to reactive world ~");
    }
}

启动服务,可以看到默认服务从Tomcat变为了netty:
在这里插入图片描述

访问URL
在这里插入图片描述

spring 对webflux进行了很好的封装,完全兼容springmvc, 使得迁移非常方便。不过底层架构已经完全不同。
整个技术栈从命令式的、同步阻塞的【spring-webmvc + servlet + Tomcat】变成了响应式的、异步非阻塞的【spring-webflux + Reactor + Netty】
Reactor 是异步非阻塞的框架,其相关内容后续会介绍

使用HandlerFunction和RouterFunction实现web服务端

实体类Stu

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Builder
public class Stu implements Serializable {
    private String name;
    private int age;
    private Date date;
    private BigDecimal b;
    private Duration d;
}

编写handle

@Component
@Slf4j
public class TimeHandler {
    public Mono<ServerResponse> getTime(ServerRequest serverRequest) {
        return ServerResponse.ok().contentType(MediaType.TEXT_PLAIN)
                .body(Mono.just("Now is " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())), String.class);
    }

    /**
     * 模拟DB获取数据
     * @param serverRequest
     * @return
     */
    public Mono<ServerResponse> getStus(ServerRequest serverRequest) {
        List<Stu> stus = Arrays.asList(Stu.builder().age(10).name("zhangsan").build(),
                Stu.builder().age(20).name("lisi").build());
        return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON)//这里改为json
                .body(Flux.just(stus), List.class);
    }
}

编写路由器

import com.example.handle.TimeHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;

import static org.springframework.web.reactive.function.server.RequestPredicates.GET;

@Configuration
public class RouterConfig {

    @Autowired
    private TimeHandler timeHandler;

    /**
     * RouterFunction: 路由
     * 相当于@RequestMapping。将不同的请求路由到不同的方法服务上
     *
     * 可以存在多个router和handler。但是bean的名称需不同(这里bean的名称使用的是方法名)
     * @return
     */
    @Bean
    public RouterFunction<ServerResponse> timerRouter() {
        return RouterFunctions.route(GET("/time"), req -> timeHandler.getTime(req))
                .andRoute(GET("/getStus"), timeHandler::getStus);
    }
}

启动服务器:
在这里插入图片描述
在这里插入图片描述

服务器推送

通常类似于聊天室之类的技术都会用到Websocket、Socket.IO(nodejs或者netty)。
响应式编程是一种基于数据流的编程范式,天然适合在服务器推送。

在handle添加一个方法,模拟一个每秒想客户端推送时间的例子

    /**
     * 服务器端推送,
     * 每秒推送当前服务器时间
     *
     * @param serverRequest
     * @return
     */
    public Mono<ServerResponse> getTimePerSecond(ServerRequest serverRequest) {
        return ServerResponse.ok().contentType(MediaType.TEXT_EVENT_STREAM)
                .body(Flux.interval(Duration.ofSeconds(1))
                                .map(a -> "Now is " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())),
                        String.class);
    }

路由中添加:

@Bean
    public RouterFunction<ServerResponse> timerRouter() {
        return RouterFunctions.route(GET("/time"), req -> timeHandler.getTime(req))
                .andRoute(GET("/getStus"), timeHandler::getStus)
                .andRoute(GET("/getTimePerSecond"), timeHandler::getTimePerSecond);
    }

访问链接会发现每隔一秒都会收到服务器推送的消息。
在这里插入图片描述

springboot系列学习笔记全部文章请移步值博主专栏**: spring boot 2.X/spring cloud Greenwich。
由于是一系列文章,所以后面的文章可能会使用到前面文章的项目。springboot系列代码全部上传至GitHub:https://github.com/liubenlong/springboot2_demo
本系列环境:Java11;springboot 2.1.1.RELEASE;springcloud Greenwich.RELEASE;MySQL 8.0.5;

你可能感兴趣的:(spring,boot,2.X/spring,cloud,Greenwich)