• spring-boot-webflux-demo-反应式接口


    Spring Framework 5包含一个新 spring-webflux 模块。该模块包含对反应式HTTP和WebSocket客户端的支持以及反应式服务器Web应用程序(包括REST,HTML浏览器和WebSocket样式交互)
    spring web-flux 支持2种不同的编程模型

    1. 支持Spring MVC @Controller 这种注解,用法大同小异
    2. 函数式 Java 8 lambda 风格的路由函数处理请求

    Spring WebFlux 是 Spring Framework 5.0中引入的新的响应式web框架。与Spring MVC不同,它不需要Servlet API,是完全异步且非阻塞的,并且通过Reactor项目实现了Reactive Streams规范。
    Spring WebFlux 用于创建基于事件循环执行模型的完全异步且非阻塞的应用程序。
    (PS:异步非阻塞是针对服务端而言的,服务端可以充分利用CPU资源去做更多事情,与客户端无关,客户端该怎么请求还是怎么请求。)
    Reactive Streams是一套用于构建高吞吐量、低延迟应用的规范。而Reactor项目是基于这套规范的实现,它是一个完全非阻塞的基础,且支持背压。Spring WebFlux基于Reactor实现了完全异步非阻塞的一套web框架,是一套响应式堆栈。
    【spring-webmvc + Servlet + Tomcat】命令式的、同步阻塞的
    【spring-webflux + Reactor + Netty】响应式的、异步非阻塞的

    参考

    Spring WebFlux 入门
    外行人都能看得懂的WebFlux,错过了血亏!
    WebFlux 示例程序

    代码

    pom

        <!--基于Springboot-->
        <parent>
            <artifactId>spring-boot-starter-parent</artifactId>
            <groupId>org.springframework.boot</groupId>
            <version>2.3.1.RELEASE</version>
            <relativePath/>
        </parent>
    
        <properties>
            <maven.compiler.source>8</maven.compiler.source>
            <maven.compiler.target>8</maven.compiler.target>
            <java.version>1.8</java.version>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
            <skipTests>true</skipTests>
    
            <spring-boot.version>2.3.1.RELEASE</spring-boot.version>
        </properties>
        <dependencies>
    <!--        异步非阻塞并不会使程序运行得更快。WebFlux 并不能使接口的响应时间缩短,它仅仅能够提升吞吐量和伸缩性。-->
    <!--        Spring WebFlux 是一个异步非阻塞的 Web 框架,所以,它特别适合应用在 IO 密集型的服务中,比如微服务网关这样的应用中。-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-webflux</artifactId>
            </dependency>
        </dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    yml

    server:
      port: 8998
    logging:
      file:
        path: ./logs
        name: spring-logs-demo.log
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    业务测试代码

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;
    
    import java.util.concurrent.TimeUnit;
    @Component
    public class BusService {
        private static final Logger log = LoggerFactory.getLogger(BusService.class);
        public String implement(String type){
            log.info("执行耗时业务,{}",type);
            try {
                TimeUnit.SECONDS.sleep(2L);
            } catch (InterruptedException e) {
                log.info("睡眠异常");
            }
            return "hello.";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    接口-注解方式

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.http.MediaType;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    import reactor.core.publisher.Flux;
    import reactor.core.publisher.Mono;
    
    import java.util.stream.IntStream;
    
    @RestController
    @RequestMapping("/root")
    public class RootController {
        private static final Logger log = LoggerFactory.getLogger(RootController.class);
        private BusService busService;
        @Autowired
        public void setBusService(BusService busService) {
            this.busService = busService;
        }
    
        @GetMapping("{id}")
        public Mono<String> hello(@PathVariable String id){
            log.info("spring-webflux 接口(方式1)-注解-start,id:{}",id);
            Mono<String> result = Mono.fromSupplier(()-> busService.implement("api1"));
            log.info("spring-webflux 接口(方式1)-注解-end");
            return result;
        }
        @GetMapping(value = "flux",produces = MediaType.TEXT_EVENT_STREAM_VALUE)
        public Flux<String> flux(){
            log.info("spring-webflux 接口(方式1)-服务器推送");
            return Flux.fromStream(IntStream.range(1,5).mapToObj(i-> busService.implement("flux") + i));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    接口-路由方式

    接口

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.http.MediaType;
    import org.springframework.stereotype.Component;
    import org.springframework.web.reactive.function.BodyInserters;
    import org.springframework.web.reactive.function.server.ServerRequest;
    import org.springframework.web.reactive.function.server.ServerResponse;
    import reactor.core.publisher.Mono;
    
    @Component
    public class RootHandler {
        private static final Logger log = LoggerFactory.getLogger(RootHandler.class);
        public Mono<ServerResponse> hello(ServerRequest request){
            String id = request.pathVariable("id");
            log.info("spring-webflux 接口(方式2)-声明式-start,id:{}",id);
            Mono<ServerResponse> mono = ServerResponse.ok().contentType(MediaType.TEXT_PLAIN)
                    .body(BodyInserters.fromValue("Hello."));
            log.info("spring-webflux 接口(方式2)-声明式-end");
            return mono;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    路由配置

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.http.MediaType;
    import org.springframework.web.reactive.function.server.RequestPredicates;
    import org.springframework.web.reactive.function.server.RouterFunction;
    import org.springframework.web.reactive.function.server.RouterFunctions;
    import org.springframework.web.reactive.function.server.ServerResponse;
    
    @Configuration
    public class RootRouter {
        private static final Logger log = LoggerFactory.getLogger(RootRouter.class);
        @Bean
        public RouterFunction<ServerResponse> router(RootHandler handler){
            log.info("spring-webflux 接口(方式2)-声明式-注入接口,{}",handler.getClass());
            return RouterFunctions.route(RequestPredicates.GET("/handler/hello/{id}")
                    .and(RequestPredicates.accept(MediaType.TEXT_PLAIN)),handler::hello);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    测试

    import org.springframework.http.MediaType;
    import org.springframework.web.reactive.function.client.ClientResponse;
    import org.springframework.web.reactive.function.client.WebClient;
    import reactor.core.publisher.Mono;
    
    public class RootWebClient {
        private final WebClient client = WebClient.create("http://localhost:8998");
        private final Mono<ClientResponse> result = client.get()
                .uri("/handler/hello/66")
                .accept(MediaType.TEXT_PLAIN).exchange();
        public String res(){
            return result.flatMap( r -> r.bodyToMono(String.class)).block();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    启动类

    import cn.demo.flux.action.RootWebClient;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class WebFluxDemoApplication {
        private static final Logger log = LoggerFactory.getLogger(WebFluxDemoApplication.class);
        public static void main(String[] args) {
            log.info("start--->");
            SpringApplication.run(WebFluxDemoApplication.class,args);
            log.info("end--->");
            String res = new RootWebClient().res();
            log.info("send--->,{}",res);
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    测试

    代码测试

    在这里插入图片描述

    请求测试-1

    在这里插入图片描述
    在这里插入图片描述

    请求测试2

    在这里插入图片描述
    在这里插入图片描述

    测试推送

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • 相关阅读:
    【最长上升子序列】【博弈论】Game on Permutation—CF1860C
    问遍了身边的面试官朋友,我整理出这份 Java 集合高频面试题(2021年最新版)
    积雪草酸肌白蛋白纳米粒|野黄芩苷豆清白蛋白纳米粒|黄芩苷蓖麻蛋白纳米粒(齐岳)
    如何创建一个SpringBoot项目
    Kubernetes技术与架构(五)
    (C++进阶)正则表达式
    Android-短信验证码
    自然语言处理应用(三):微调BERT
    从 wepy 到 uniapp 变形记
    内网渗透之Linux反弹shell(二)
  • 原文地址:https://blog.csdn.net/privateobject/article/details/125507925