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

29 篇文章 0 订阅
23 篇文章 0 订阅

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>

yml

server:
  port: 8998
logging:
  file:
    path: ./logs
    name: spring-logs-demo.log

业务测试代码

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.";
    }
}

接口-注解方式

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));
    }
}

接口-路由方式

接口

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;
    }
}

路由配置

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);
    }
}

测试

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();
    }
}

启动类

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

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

测试推送

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值