响应式编程WebFlux基础API

WebFlux的工作流程

在WebFlux中,主要的组件包括:

  • Reactor: Reactor是WebFlux底层使用的响应式编程库,提供了MonoFlux这两种响应式类型,分别用于表示0-1个和0-N个异步序列元素。
  • WebHandler: 是处理请求的核心接口,所有的请求都会被分配给一个WebHandler来处理。
  • HandlerMapping: 用于将请求映射到对应的WebHandler
  • HandlerAdapter: 用于适配WebHandler的执行,使其能够处理请求并返回响应。
  • WebFilter: 类似于Servlet中的Filter,可以在请求处理前后进行拦截和处理。
  • ServerResponseServerRequest: 分别代表HTTP的响应和请求,在WebFlux中用于处理非阻塞的请求和响应。
  • RouterFunction: 用于声明式地定义路由规则,将请求映射到处理器函数。

工作流程图

Request
Dispatch
Map to
Filter
Process
Response
Return
Use
Async Processing
Client
Server
HandlerMapping
WebHandler
WebFilter
HandlerAdapter
ServerResponse
Reactor

在这个流程中:

  1. 客户端发送请求到服务器。
  2. 服务器接收到请求,并将其分发给HandlerMapping
  3. HandlerMapping根据请求信息将其映射到对应的WebHandler
  4. WebFilter可以在请求到达WebHandler之前或之后进行拦截和处理。
  5. WebHandler处理请求,可能会使用Reactor库中的MonoFlux进行异步处理。
  6. HandlerAdapterWebHandler的处理结果适配成服务器可以发送的响应。
  7. ServerResponse将响应返回给客户端。

WebFlux核心API

1. HttpHandler与HttpServer

HttpHandler

HttpHandler是WebFlux中处理HTTP请求的核心接口之一。它代表一个能够处理HTTP请求并生成响应的组件。HttpHandler可以被看作是一个函数,接受一个HTTP请求并返回一个表示HTTP响应的Publisher。典型的HttpHandler可以是一个Lambda表达式或一个实现了接口的类。可用于 Reactor Netty 的适配器, Undertow、Tomcat、Jetty 和任何 Servlet 容器。

HttpServer

HttpServer是Reactor Netty提供的一个用于构建HTTP服务器的类。它允许你配置服务器的主机名、端口、SSL支持等信息。

public class SimpleHttpHandlerServerExample {

    public static void main(String[] args) throws IOException {
        HttpHandler httpHandler = RouterFunctions.toHttpHandler(
                RouterFunctions.route()
                        .GET("/hello", request -> ServerResponse.ok().bodyValue("Hello, WebFlux!"))
                        .build());

        ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(httpHandler);

        //启动Netty服务器
        HttpServer.create()
                .host("localhost")
                .port(8080)
                .handle(adapter) //用指定的处理器处理请求
                .bindNow(); //现在就绑定

        System.out.println("服务器启动完成....监听8080,接受请求");
        System.in.read();
        System.out.println("服务器停止....");
    }
}

测试

GET http://localhost:8080/hello 响应:Hello, WebFlux!

2. DispatcherHandler

前中讲到WebFlux的工作流程第5步中WebHandler用于处理请求

在 Spring WebFlux 中,DispatcherHandler 实现了 WebHandler 接口,因此 DispatcherHandlerWebHandler 的一种具体实现。 WebHandler 接口定义了处理 HTTP 请求的方法,而 DispatcherHandler 实现了这个接口,提供了处理请求的具体实现。

WebHandler 接口的主要方法是 handle,用于处理 HTTP 请求。DispatcherHandler 通过实现这个接口,提供了对请求的分发和处理的支持。下面是 WebHandler 接口的声明:

public interface WebHandler {
    Mono<Void> handle(ServerWebExchange exchange);
}

DispatcherHandler 通过实现 WebHandler 接口,定义了处理请求的具体逻辑。在 DispatcherHandler 中,handle 方法被实现为请求的分发和处理,如代码所示。

@Override
public Mono<Void> handle(ServerWebExchange exchange) {
    // 如果 handlerMappings 为 null,返回一个包含错误信息的 Mono
    if (this.handlerMappings == null) {
        return createNotFoundError();
    }
    
    // 如果是预检请求(CORS pre-flight request),处理预检请求
    if (CorsUtils.isPreFlightRequest(exchange.getRequest())) {
        return handlePreFlight(exchange);
    }

    // 从 handlerMappings 中获取处理器函数
    return Flux.fromIterable(this.handlerMappings)
            // 依次尝试每个 HandlerMapping,获取处理器函数(是开发者编写的处理器函数,Controller中的接口),也是工作流程中第3步
            .concatMap(mapping -> mapping.getHandler(exchange)) 
            // 取第一个非空的处理器函数,如果都为空,则返回 createNotFoundError
            .next()
            // 如果获取处理器函数失败,也返回 createNotFoundError
            .switchIfEmpty(createNotFoundError())
            // 处理可能发生的错误,比如处理器函数执行时的异常
            .onErrorResume(ex -> handleDispatchError(exchange, ex))
            // 处理请求,传递 ServerWebExchange 和处理器函数
            .flatMap(handler -> handleRequestWith(exchange, handler));
}

所以,DispatcherHandlerWebHandler 的一种实现,用于实现对请求的分发和处理。在 Spring WebFlux 中,DispatcherHandler 是整个请求处理流程的核心组件之一。

WebFlux常用API

1. RouterFunctions

RouterFunctions 是用于定义路由的主要接口。通过它,你可以定义请求的映射和处理。

@Configuration
public class MyRouterConfig {

    @Bean
    public RouterFunction<ServerResponse> myRoutes(MyHandler handler) {
        return RouterFunctions.route(GET("/api/resource/{id}"), handler::handleResource)
                .andRoute(POST("/api/resource"), handler::createResource);
    }
}

2. HandlerFunction

HandlerFunction 用于处理请求,并返回响应。你需要为每个路由定义一个处理函数。

@Component
public class MyHandler {

    public Mono<ServerResponse> handleResource(ServerRequest request) {
        // 处理 GET 请求逻辑
        // 返回 Mono<ServerResponse>
        String resourceId = request.pathVariable("id");
        WebClient webClient = WebClient.create("http://localhost:8080");

        webClient.get()
                .uri("/api/resource/{id}", 123)
                .retrieve()
                .bodyToMono(String.class)
                .subscribe(response -> System.out.println("Response: " + response));
        // 处理逻辑
        return ServerResponse.ok().bodyValue("Resource ID: " + resourceId);
    }

    public Mono<ServerResponse> createResource(ServerRequest request) {
        // 处理 POST 请求逻辑
        // 返回 Mono<ServerResponse>
        return Mono.just("Hello, WebFlux!")
                .flatMap(response -> ServerResponse.ok().bodyValue(response));
    }
}

3. ServerRequest 和 ServerResponse

ServerRequest 表示一个 HTTP 请求,而 ServerResponse 表示一个 HTTP 响应。在处理函数中,你可以通过这两个对象来获取请求信息和构建响应。

    public Mono<ServerResponse> handleResource(ServerRequest request) {
        // 处理 GET 请求逻辑
        // 返回 Mono<ServerResponse>
        String resourceId = request.pathVariable("id");
        WebClient webClient = WebClient.create("http://localhost:8080");

        webClient.get()
                .uri("/api/resource/{id}", 123)
                .retrieve()
                .bodyToMono(String.class)
                .subscribe(response -> System.out.println("Response: " + response));
        // 处理逻辑
        return ServerResponse.ok().bodyValue("Resource ID: " + resourceId);
    }

4. Mono 和 Flux

MonoFlux 是 Reactor 框架中的概念,但在 Spring WebFlux 中也经常用到。Mono 用于表示包含零个或一个元素的异步序列,而 Flux 用于表示包含零个或多个元素的异步序列。

    public Mono<ServerResponse> createResource(ServerRequest request) {
        // 处理 POST 请求逻辑
        // 返回 Mono<ServerResponse>
        return Mono.just("Hello, WebFlux!")
                .flatMap(response -> ServerResponse.ok().bodyValue(response));
    }

5. WebClient

WebClient 是 Spring WebFlux 提供的用于进行 HTTP 请求的客户端。它支持异步和响应式编程。

    public Mono<ServerResponse> handleResource(ServerRequest request) {
        // 处理 GET 请求逻辑
        // 返回 Mono<ServerResponse>
        String resourceId = request.pathVariable("id");
        WebClient webClient = WebClient.create("http://localhost:8080");

        webClient.get()
                .uri("/api/resource/{id}", 123)
                .retrieve()
                .bodyToMono(String.class)
                .subscribe(response -> System.out.println("Response: " + response));
        // 处理逻辑
        return ServerResponse.ok().bodyValue("Resource ID: " + resourceId);
    }

6. MediaType 和 Content-Type

MediaType 类用于表示媒体类型,而 Content-Type 则是 HTTP 请求和响应中用于指定实体主体的媒体类型。

public Mono<ServerResponse> handleResource(ServerRequest request) {
    return ServerResponse.ok()
            .contentType(MediaType.APPLICATION_JSON)
            .bodyValue("{ \"message\": \"Hello, WebFlux!\" }");
}

7. ExceptionHandler

ExceptionHandler 用于全局处理异常,你可以通过实现 WebExceptionHandler 接口来自定义异常处理逻辑。

@Component
@Order(-2) // 定义处理器的顺序
public class GlobalExceptionHandler implements WebExceptionHandler {

    @Override
    public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
        // 处理其他异常
        exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
        return exchange.getResponse().setComplete();
    }
}

8. ServerSentEvent(SSE)

SSE(Server-Sent Events,服务器推送事件)是一种用于在客户端和服务器之间实现单向实时通信的Web技术。它允许服务器将实时信息推送到客户端,而不需要客户端显式请求。SSE建立在HTTP协议之上,使用简单的文本格式进行通信。

SSE的主要特点包括:

  1. 单向通信: SSE是一种单向通信机制,只允许服务器向客户端推送数据。客户端不能向服务器发送信息。这使得它适用于实时通知、事件更新等场景。

  2. 基于文本: SSE 使用文本格式进行通信,数据以文本的形式发送到客户端。这种简单的文本格式使得 SSE 对于实时通信来说非常轻量,适用于传递简单的实时信息。

  3. 自动重连: SSE 支持自动重连机制。如果连接中断,客户端会尝试重新连接到服务器,保持实时通信的连续性。

  4. 事件流: 服务器通过发送事件流(event stream)来向客户端推送信息。每个事件可以包含一个数据字段、事件标识符、事件类型等信息。

一个简单的 SSE 事件看起来可能像这样:

event: eventType
id: eventID
data: Some message
  • event 字段表示事件类型。
  • id 字段是可选的,表示事件的唯一标识符。
  • data 字段包含实际的事件数据。

在Java中使用Spring WebFlux框架时,你可以使用 ServerSentEvent 类型来表示 SSE 事件,如前面提到的代码示例所示。 SSE 在前端通常通过 JavaScript 的 EventSource API 进行处理。

SSE 是一种相对简单且易于实现的实时通信机制,适用于需要从服务器向客户端推送实时信息的场景,比如实时通知、实时更新等。

    @GetMapping(value = "/sse",produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<ServerSentEvent<String>> sse(){
        return Flux.range(1,10)
                .map(i-> {

                    //构建一个SSE对象
                    return    ServerSentEvent.builder("ha-" + i)
                            .id(i + "")
                            .comment("hei-" + i)
                            .event("haha")
                            .build();
                })
                .delayElements(Duration.ofMillis(500));
    }
  1. @GetMapping(value = "/sse", produces = MediaType.TEXT_EVENT_STREAM_VALUE): 这是一个Spring WebFlux中的注解,指定了处理GET请求的路径为"/sse",并且设置produces属性为MediaType.TEXT_EVENT_STREAM_VALUE,表示这个接口产生的是一个SSE流。

  2. Flux.range(1, 10): 这个方法创建了一个包含从1到10的整数的Flux。在这个例子中,它表示将要推送的事件的序列。

  3. map(i -> { ... }): 这是一个Flux的转换操作,将上述的整数序列映射为Server-Sent Event对象的序列。

  4. ServerSentEvent.builder("ha-" + i): 这是Server-Sent Event对象的构建器。通过这个构建器,可以设置SSE事件的各种属性,比如数据(“ha-” + i)、事件ID(i + “”)、注释(“hei-” + i)、事件类型(“haha”)等。

  5. .delayElements(Duration.ofMillis(500)): 这个方法引入了一个延迟,表示每个事件之间的时间间隔为500毫秒。这样可以模拟实时数据的推送,每500毫秒推送一个事件。

最终,这个方法返回一个Flux<ServerSentEvent<String>>,表示一个Server-Sent Events流,其中包含了一系列的SSE事件。这个流会被Spring WebFlux框架自动转换为SSE格式,然后通过HTTP协议发送到客户端。客户端可以通过订阅这个SSE端点,实时接收服务器推送的事件数据。

9. WebFluxConfigurer

WebFluxConfigurer 接口提供了一系列回调方法,允许你在Spring WebFlux应用程序中进行配置和扩展。

@Configuration
public class MyWebConfiguration {

    /**
     * 自定义WebFlux配置
     * @return
     */
    @Bean
    public WebFluxConfigurer webFluxConfigurer() {
        return new WebFluxConfigurer() {
            @Override
            public void configureContentTypeResolver(RequestedContentTypeResolverBuilder builder) {
                // 配置内容类型解析器
                // builder.xxx(...);
            }

            @Override
            public void addCorsMappings(CorsRegistry registry) {
                // 配置全局跨域规则
                registry.addMapping("/api/**")
                        .allowedOrigins("https://example.com")
                        .allowedMethods("GET", "POST");
            }

            @Override
            public void configurePathMatching(PathMatchConfigurer configurer) {
                // 配置路径匹配选项
                // configurer.xxx(...);
            }

            @Override
            public void addResourceHandlers(ResourceHandlerRegistry registry) {
                // 配置静态资源处理器
                registry.addResourceHandler("/static/**")
                        .addResourceLocations("classpath:/static/");
            }

            @Override
            public void configureArgumentResolvers(ArgumentResolverConfigurer configurer) {
                // 配置自定义参数解析器
                // configurer.xxx(...);
            }

            @Override
            public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
                // 配置HTTP消息编解码器
                // configurer.xxx(...);
            }

            @Override
            public void addFormatters(FormatterRegistry registry) {
                // 添加自定义格式化器
                // registry.xxx(...);
            }

            @Override
            public Validator getValidator() {
                // 提供自定义的验证器
                // return new MyValidator();
                return null;
            }

            @Override
            public MessageCodesResolver getMessageCodesResolver() {
                // 提供自定义的消息码解析器
                // return new MyMessageCodesResolver();
                return null;
            }

            @Override
            public WebSocketService getWebSocketService() {
                // 提供自定义的WebSocket服务
                // return new MyWebSocketService();
                return null;
            }

            @Override
            public void configureViewResolvers(ViewResolverRegistry registry) {
                // 配置视图解析器
                // registry.xxx(...);
            }
        };
    }
}

10. WebFilter

WebFilter 是 Spring WebFlux 中的一个接口,用于实现基于函数式编程的全局过滤器,用于在请求进入 WebFlux 路由之前或者响应返回给客户端之前执行一些预处理或后处理逻辑。全局过滤器可以对请求和响应进行修改、记录日志、添加头信息等操作。

@Component
public class MyWebFilter implements WebFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();

        System.out.println("请求处理放行到目标方法之前...");
        Mono<Void> filter = chain.filter(exchange); //放行


        //流一旦经过某个操作就会变成新流
        Mono<Void> voidMono = filter.doOnError(err -> {
                    System.out.println("目标方法异常以后...");
                }) // 目标方法发生异常后做事
                .doFinally(signalType -> {
                    System.out.println("目标方法执行以后...");
                });// 目标方法执行之后

        //上面执行不花时间。
        return voidMono; //看清楚返回的是谁!!!
    }
}

11. @EnableWebFlux

开启WebFlux自定义; 禁用WebFLux的默认效果,完全自定义,所有WebFluxAutoConfiguration 配置默认效果全部失效,一般不用

@SpringBootApplication
@EnableWebFlux
public class WebFluxMainApplication {

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

学习打卡day09:响应式编程WebFlux基础API

  • 30
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

摸魚散人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值