在Spring WebFlux Web服务中使用Server-Sent Events来实现Hello World

在Spring WebFlux Web服务中使用Server-Sent Events实现”Hello World”。

spring-boot_on_ubuntu.png

这个问题的目标是什么?

我将使用 Windows 11 上的 Linux 进行云开发。

您可以在这里查看文章的列表。

 

实现

在Ubuntu操作系统上,验证Spring WebFlux应用程序的Server-Sent Events功能。

技术主题

什么是Spring WebFlux?

您可以展开查看这里。Spring WebFlux

这是Spring Framework的一个模块,用于开发异步和响应式的Web应用程序。

关键词
内容

异步和响应式的请求处理
Spring WebFlux可以使用称为响应式流的机制来异步处理请求。这样可以在资源较少的情况下实现高吞吐量。

WebFlux服务器
Spring WebFlux包含基于Netty的WebFlux服务器。该服务器可以实现高吞吐量和低延迟。

支持Reactive Streams API
Spring WebFlux符合Reactive Streams API规范,可以与其他使用Reactive Streams API的库进行集成。这样可以开发出更灵活和可扩展的应用程序。

服务器推送事件 (Server-Sent Events, SSE) 是什么?

可以展开并查看此处。服务器推送事件

服务器推送事件(SSE)是一种专门用于服务器向客户端进行单向实时通信的技术,服务器可以实时推送更新信息给客户端。通过维持长时间连接,客户端可以实时接收来自服务器的更新信息。
SSE适用于需要实时信息传递的Web应用程序。例如,下面是一些可能使用SSE的情况的关键词与内容。

关键词 内容

社交媒体的实时更新 像社交媒体这样的Web应用程序需要实时更新用户发布的新信息、关注人的活动情况等。通过使用SSE,服务器可以在收到新信息时推送给客户端。

股票信息的实时更新 在像股票市场这样的行业中,需要实时获取股票价格的变动等信息。通过使用SSE,可以实时推送股价和交易更新信息。

在线游戏的实时更新 在线游戏需要实时传递玩家的动作和其他玩家的行为等实时信息。通过使用SSE,可以向玩家实时传递信息。

这些只是一些例子,各种需要实时信息传递的Web应用程序中都可能会使用SSE。

开发环境

    Windows 11 Home 22H2 を使用しています。
可以参考 macOS 的操作方式,因为我会操作 WSL 中的 Ubuntu。
WSL(Microsoft Store应用版)※您可以在相关文章中查找安装方法:
> wsl –version
WSL版本:1.0.3.0
内核版本:5.15.79.1
WSLg版本:1.0.47Ubuntu ※您可以在相关文章中查找安装方法:
$ lsb_release -a
没有可用的LSB模块。
发行商ID:Ubuntu
描述:Ubuntu 22.04.1 LTS
发行版本:22.04

Java JDK ※您可以在相关文章中查找安装方法:
$ java -version
openjdk version “17.0.6” 2023-01-17
OpenJDK Runtime Environment GraalVM CE 22.3.1(build 17.0.6+10-jvmci-22.3-b13)
OpenJDK 64位服务器VM GraalVM CE 22.3.1(build 17.0.6+10-jvmci-22.3-b13,混合模式,共享)

Maven ※您可以在相关文章中查找安装方法:
$ mvn -version
Apache Maven 3.6.3
Maven主目录:/usr/share/maven
Java版本:11.0.18,供应商:Ubuntu,运行时:/usr/lib/jvm/java-11-openjdk-amd64

在這篇文章中,我們基本上是在 Ubuntu 終端機中進行操作。為了讓初學者學習使用 Vim 進行複製貼上,我們在下面的文章中介紹了相關步驟。請勇於嘗試。

 

创建Web应用程序的规格

NoフレームワークエンドポイントHTTPメソッドMIME タイプ1Spring MVC/oneGETapplication/json2Spring MVC/listGETapplication/json3Spring WebFlux/monoGETapplication/json4Spring WebFlux/fluxGETapplication/json5Spring WebFlux/flux-sseGETtext/event-stream

并行处理

创建Spring MVC Web服务

这将使用Spring Boot创建。如果不需要特别注意,可以跳过阅读,因为此项目是为了比较同步和异步处理而创建的。
可以展开这里查看。创建项目文件夹
创建项目文件夹。
※将~/tmp/sync-spring-mvc设置为项目文件夹。
$ mkdir -p ~/tmp/sync-spring-mvc
$ cd ~/tmp/sync-spring-mvc

创建应用程序类
创建应用程序类。

为了简化项目结构,将所有元素都写入Application类。

$ mkdir -p src/main/java/com/example/springmvc
$ vim src/main/java/com/example/springmvc/Application.java

文件内容

Application.java
package com.example.springmvc;

import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController
@SpringBootApplication
public class Application {

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

@GetMapping(“/one”)
public Map<String, String> getOne() throws InterruptedException {
Map<String, String> map = Map.of(“message”, “Hello Object!”);
TimeUnit.SECONDS.sleep(2);
log.info(“Sending message: {}”, map);
return map;
}

@GetMapping(“/list”)
public List<Map<String, String>> getList() throws InterruptedException {
List<Map<String, String>> list = List.of(
Map.of(“message”, “Hello List 1!”),
Map.of(“message”, “Hello List 2!”),
Map.of(“message”, “Hello List 3!”),
Map.of(“message”, “Hello List 4!”),
Map.of(“message”, “Hello List 5!”));
list.forEach(map -> {
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
log.error(e.getMessage());
throw new RuntimeException(e);
}
log.info(“Sending message: {}”, map);
});
return list;
}
}

每个处理都设置了2秒的延迟。

创建pom.xml
创建pom.xml文件。
$ vim pom.xml

文件内容

pom.xml

4.0.0
org.springframework.boot
spring-boot-starter-parent
2.7.8

com.example
sync-spring-mvc
1.0
sync-spring-mvc

11
UTF-8

org.springframework.boot
spring-boot-starter-web

org.projectlombok
lombok
1.18.26
provided

app
org.springframework.boot
spring-boot-maven-plugin

配置输出日志文件

application.properties
logback-spring.xml

您可以在以下相关文章中查看详细步骤。
https://qiita.com/fsdg-adachi_h/items/ffbcb6ac9179852b2816

构建应用程序
构建Java应用程序。
※将创建target/app.jar。
$ mvn clean install

启动应用程序
启动应用程序。
※按Ctrl + C停止应用程序。
$ rm -rf log
$ mvn spring-boot:run

应用程序的功能验证

我們可以從另一個終端窗口使用curl命令來進行確認。

如果获取到一个对象(Map)的情况下。

$ curl -v http://localhost:8080/one -w '\n'
*   Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /one HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.81.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200
< Content-Type: application/json
< Transfer-Encoding: chunked
< Date: Mon, 20 Mar 2023 03:53:45 GMT
<
* Connection #0 to host localhost left intact
{"message":"Hello Object!"}

我会从不同的终端查看日志文件。※ 这里只摘录了必要的部分。

$ cd ~/tmp/sync-spring-mvc/log
$ cat app.log
2023-03-20 13:05:32.679 [INFO ] [main] org.springframework.boot.web.embedded.tomcat.TomcatWebServer.start:220 - Tomcat started on port(s): 8080 (http) with context path ''
2023-03-20 13:05:32.686 [INFO ] [main] org.springframework.boot.StartupInfoLogger.logStarted:61 - Started Application in 0.954 seconds (JVM running for 1.11)
2023-03-20 13:05:45.910 [INFO ] [http-nio-8080-exec-1] org.springframework.web.servlet.FrameworkServlet.initServletBean:525 - Initializing Servlet 'dispatcherServlet'
2023-03-20 13:05:45.913 [INFO ] [http-nio-8080-exec-1] org.springframework.web.servlet.FrameworkServlet.initServletBean:547 - Completed initialization in 1 ms
2023-03-20 13:05:47.930 [INFO ] [http-nio-8080-exec-1] com.example.springmvc.Application.getOne:26 - Sending message: {message=Hello Object!}
根据线程名称 http-nio-8080-exec-1,可以推断出该线程是由 Spring MVC 的 Tomcat 进行处理。

如果获取列表

我們將使用curl命令從另一個終端窗口進行驗證。

$ curl -v http://localhost:8080/list -w '\n'
*   Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /list HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.81.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200
< Content-Type: application/json
< Transfer-Encoding: chunked
< Date: Mon, 20 Mar 2023 03:56:19 GMT
<
* Connection #0 to host localhost left intact
[{"message":"Hello List 1!"},{"message":"Hello List 2!"},{"message":"Hello List 3!"},{"message":"Hello List 4!"},{"message":"Hello List 5!"}]

我会从另一个终端检查日志文件。※仅提取必要的部分。

$ cd ~/tmp/sync-spring-mvc/log
$ cat app.log
2023-03-20 13:06:34.424 [INFO ] [main] org.springframework.boot.web.embedded.tomcat.TomcatWebServer.start:220 - Tomcat started on port(s): 8080 (http) with context path ''
2023-03-20 13:06:34.430 [INFO ] [main] org.springframework.boot.StartupInfoLogger.logStarted:61 - Started Application in 0.947 seconds (JVM running for 1.102)
2023-03-20 13:06:38.337 [INFO ] [http-nio-8080-exec-1] org.springframework.web.servlet.FrameworkServlet.initServletBean:525 - Initializing Servlet 'dispatcherServlet'
2023-03-20 13:06:38.340 [INFO ] [http-nio-8080-exec-1] org.springframework.web.servlet.FrameworkServlet.initServletBean:547 - Completed initialization in 1 ms
2023-03-20 13:06:40.522 [INFO ] [http-nio-8080-exec-1] com.example.springmvc.Application.lambda$getList$0:45 - Sending message: {message=Hello List 1!}
2023-03-20 13:06:42.691 [INFO ] [http-nio-8080-exec-1] com.example.springmvc.Application.lambda$getList$0:45 - Sending message: {message=Hello List 2!}
2023-03-20 13:06:44.721 [INFO ] [http-nio-8080-exec-1] com.example.springmvc.Application.lambda$getList$0:45 - Sending message: {message=Hello List 3!}
2023-03-20 13:06:46.740 [INFO ] [http-nio-8080-exec-1] com.example.springmvc.Application.lambda$getList$0:45 - Sending message: {message=Hello List 4!}
2023-03-20 13:06:48.748 [INFO ] [http-nio-8080-exec-1] com.example.springmvc.Application.lambda$getList$0:45 - Sending message: {message=Hello List 5!}
可以推测出根据线程名称为 http-nio-8080-exec-1,该线程是由 Spring MVC 的 Tomcat 进行处理的。数据会在一段时间后一次性地从客户端(使用 curl)获取。

总结到这里

在Spring MVC中,我们使用Tomcat作为内置的Web服务器。List对象正在同步处理。

异步处理

创建Spring WebFlux Web服务

用Spring Boot进行创建。

创建项目文件夹

创建项目文件夹。
※ 将~/tmp/async-spring-webflux设为项目文件夹。

$ mkdir -p ~/tmp/async-spring-webflux
$ cd ~/tmp/async-spring-webflux

创建应用程序类

创建一个应用程序类。

为了简化项目结构,我们将所有元素都写在了Application类中。
$ mkdir -p src/main/java/com/example/springwebflux
$ vim src/main/java/com/example/springwebflux/Application.java

文件的内容 de

package com.example.springwebflux;

import java.time.Duration;
import java.util.Map;

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.http.codec.ServerSentEvent;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@CrossOrigin(origins = "*", allowedHeaders = "*")
@RestController
@SpringBootApplication
public class Application {

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

    @GetMapping("/mono")
    public Mono<Map<String, String>> getMono() {
        return Mono.just(
            Map.of("message", "Hello Mono!"))
            .delayElement(Duration.ofSeconds(2))
            .doOnNext(map -> log.info("Sending message: {}", map));
    }

    @GetMapping("/flux")
    public Flux<Map<String, String>> getFlux() {
        return Flux.range(1, 5)
            .map(idx -> Map.of("message", "Hello Flux " + idx + "!"))
            .delayElements(Duration.ofSeconds(2))
            .doOnNext(map -> log.info("Sending message: {}", map));
    }

    @GetMapping("/flux-sse")
    public Flux<ServerSentEvent<Map<String, String>>> getFluxWithSSE() {
        return Flux.range(1, 5)
            .map(idx -> Map.of("message", "Hello Flux " + idx + "!"))
            .delayElements(Duration.ofSeconds(2))
            .doOnNext(map -> log.info("Sending message: {}", map))
            .map(map -> ServerSentEvent.builder(map).build())
            .concatWith(Mono.just(ServerSentEvent.<Map<String, String>>builder().event("end").build()));
    }
}
每个处理步骤都设置了2秒的延迟时间。
在使用Spring WebFlux实现服务器端的SSE时,接收方的客户端需要明确地发送事件:end。
開啟說明。返回給客戶端非同步的單一值回應的端點
@GetMapping(“/mono”)
public Mono<Map<String, String>> getMono() {
return Mono.just(
Map.of(“message”, “Hello Mono!”))
.delayElement(Duration.ofSeconds(2))
.doOnNext(map -> log.info(“Sending message: {}”, map));
}

內容

@GetMapping(“/mono”)註釋會將HTTP GET請求映射到”/mono”端點。

Mono<Map<String, String>> 是一個表示單一非同步值的Reactive Streams類型。在這種情況下,它表示單一個Map對象。

Mono.just(Map.of(“message”, “Hello Mono!”)) 創建一個包含”message”鍵和其值的Map對象,並將其包裝到Mono中返回。

.delayElement(Duration.ofSeconds(2)) 是轉換Mono以使回應延遲2秒的運算符。

.doOnNext(map -> log.info(“Sending message: {}”, map)) 是為了將每個值通知到log對象並輸出消息而添加的副作用運算符。

換句話說,這個端點將在等待2秒後返回包含”Hello Mono!”消息的Map對象。同時,日誌將輸出”Sending message: {message=Hello Mono!}”的消息當值被通知時。

返回給客戶端非同步的多個值回應的端點
@GetMapping(“/flux”)
public Flux<Map<String, String>> getFlux() {
return Flux.range(1, 5)
.map(idx -> Map.of(“message”, “Hello Flux ” + idx + “!”))
.delayElements(Duration.ofSeconds(2))
.doOnNext(map -> log.info(“Sending message: {}”, map));
}

內容

@GetMapping(“/flux”)註釋將HTTP GET請求映射到”/flux”端點。

Flux<Map<String, String>> 是一個使用Reactive Streams類型表示多個非同步值的端點。在這種情況下,它表示多個Map對象。

Flux.range(1, 5) 產生從1到5的整數的Flux。

.map(idx -> Map.of(“message”, “Hello Flux ” + idx + “!”)) 是用於創建每個元素的包含”message”鍵和其值的Map對象的運算符。

.delayElements(Duration.ofSeconds(2)) 是延遲每個元素2秒的運算符。

.doOnNext(map -> log.info(“Sending message: {}”, map)) 是為了將每個元素通知到log對象並輸出消息而添加的副作用運算符。

換句話說,這個端點將返回包含在2秒間隔通知的每個元素中的”Hello Flux {index}!”消息的Map對象。同時,日誌將在每個值被通知時輸出”Sending message: {message=Hello Flux {index}!}”的消息。

返回使用Server-Sent Events(SSE)協議非同步發送數據給客戶端的端點
@GetMapping(“/flux-sse”)
public Flux<ServerSentEvent<Map<String, String>>> getFluxWithSSE() {
return Flux.range(1, 5)
.map(idx -> Map.of(“message”, “Hello Flux ” + idx + “!”))
.delayElements(Duration.ofSeconds(2))
.doOnNext(map -> log.info(“Sending message: {}”, map))
.map(map -> ServerSentEvent.builder(map).build())
.concatWith(Mono.just(ServerSentEvent.<Map<String, String>>builder().event(“end”).build()));
}

內容

@GetMapping(“/flux-sse”) 註釋將HTTP GET請求映射到”/flux-sse”端點。

Flux<ServerSentEvent<Map<String, String>>> 是一個使用Server-Sent Events表示多個非同步值的Reactive Streams類型。在這種情況下,它表示多個Map對象。

Flux.range(1, 5) 產生從1到5的整數的Flux。

.map(idx -> Map.of(“message”, “Hello Flux ” + idx + “!”)) 是用於創建每個元素的包含”message”鍵和其值的Map對象的運算符。

.delayElements(Duration.ofSeconds(2)) 是延遲每個元素2秒的運算符。

.doOnNext(map -> log.info(“Sending message: {}”, map)) 是為了將每個元素通知到log對象並輸出消息而添加的副作用運算符。

.map(map -> ServerSentEvent.builder(map).build()) 是將每個Map對象轉換為ServerSentEvent對象的運算符。

.concatWith(Mono.just(ServerSentEvent.<Map<String, String>>builder().event(“end”).build())) 是用於在流的末尾添加ServerSentEvent對象的運算符。這樣可以發送表示SSE流結束的event: end標籤。

換句話說,這個端點將返回使用Server-Sent Events格式包含”Hello Flux {index}!”消息的Map對象的多個值,每個元素之間間隔2秒通知。同時,日誌將在每個值被通知時輸出”Sending message: {message=Hello Flux {index}!}”的消息。

创建 pom.xml 文件

创建 pom.xml 文件。

$ vim pom.xml

文件的内容 de

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.8</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>sync-spring-webflux</artifactId>
    <version>1.0</version>
    <name>sync-spring-webflux</name>

    <properties>
        <java.version>11</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>
        <!-- Lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.26</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <build>
        <finalName>app</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

输出日志文件的设置

    • application.properties

 

    logback-spring.xml

您可以在这篇相关文章中确认步骤。

 

应用程序的构建

构建Java应用程序。
※ 将创建目标/app.jar。

$ mvn clean package

打开应用

启动应用程序。
※ 停止应用程序时按下 ctrl + C。

$ rm -rf log
$ mvn spring-boot:run

确认应用的运行情况

我們可以從另一個終端窗口使用curl命令進行確認。

如果以常规方式使用 HTTP 请求 Mono 的情况

$ curl -v http://localhost:8080/mono -w '\n'
*   Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /mono HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.81.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Vary: Origin
< Vary: Access-Control-Request-Method
< Vary: Access-Control-Request-Headers
< Content-Type: application/json
< Content-Length: 25
<
* Connection #0 to host localhost left intact
{"message":"Hello Mono!"}

我会从另一个终端查看日志文件。※ 只摘录了必要的部分。

$ cd ~/tmp/async-spring-webflux/log
$ cat app.log
2023-03-20 12:11:59.869 [DEBUG] [main] org.springframework.boot.StartupInfoLogger.logStarting:56 - Running with Spring Boot v2.7.8, Spring v5.3.25
2023-03-20 12:11:59.870 [INFO ] [main] org.springframework.boot.SpringApplication.logStartupProfileInfo:637 - The following 1 profile is active: "develop"
2023-03-20 12:12:00.556 [INFO ] [main] org.springframework.boot.web.embedded.netty.NettyWebServer.start:111 - Netty started on port 8080
2023-03-20 12:12:00.562 [INFO ] [main] org.springframework.boot.StartupInfoLogger.logStarted:61 - Started Application in 0.987 seconds (JVM running for 1.221)
2023-03-20 12:15:32.844 [INFO ] [parallel-1] com.example.springwebflux.Application.lambda$getMono$0:32 - Sending message: {message=Hello Mono!}
从线程名称 “parallel-1” 可以推断出 Spring WebFlux 在并行处理线程上处理 Mono。

如果使用普通的HTTP请求Flux的情况下

我会从另一个终端使用curl命令进行确认。

$ curl -v http://localhost:8080/flux -w '\n'
*   Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /flux HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.81.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< transfer-encoding: chunked
< Vary: Origin
< Vary: Access-Control-Request-Method
< Vary: Access-Control-Request-Headers
< Content-Type: application/json
<
* Connection #0 to host localhost left intact
[{"message":"Hello Flux 1!"},{"message":"Hello Flux 2!"},{"message":"Hello Flux 3!"},{"message":"Hello Flux 4!"},{"message":"Hello Flux 5!"}]

我会从另一个终端检查日志文件。※ 我提取了必要的内容。

$ cd ~/tmp/async-spring-webflux/log
$ cat app.log
2023-03-20 12:19:28.477 [INFO ] [main] org.springframework.boot.web.embedded.netty.NettyWebServer.start:111 - Netty started on port 8080
2023-03-20 12:19:28.482 [INFO ] [main] org.springframework.boot.StartupInfoLogger.logStarted:61 - Started Application in 0.95 seconds (JVM running for 1.124)
2023-03-20 12:19:42.389 [INFO ] [parallel-1] com.example.springwebflux.Application.lambda$getFlux$2:40 - Sending message: {message=Hello Flux 1!}
2023-03-20 12:19:44.392 [INFO ] [parallel-2] com.example.springwebflux.Application.lambda$getFlux$2:40 - Sending message: {message=Hello Flux 2!}
2023-03-20 12:19:46.394 [INFO ] [parallel-3] com.example.springwebflux.Application.lambda$getFlux$2:40 - Sending message: {message=Hello Flux 3!}
2023-03-20 12:19:48.396 [INFO ] [parallel-4] com.example.springwebflux.Application.lambda$getFlux$2:40 - Sending message: {message=Hello Flux 4!}
2023-03-20 12:19:50.399 [INFO ] [parallel-5] com.example.springwebflux.Application.lambda$getFlux$2:40 - Sending message: {message=Hello Flux 5!}
根据线程名称为parallel-n的提示,可以推测Spring WebFlux以并行处理线程的方式处理Flux每2秒钟的数据。客户端(curl)在一段时间后一次性获取数据。

如果使用Server-Sent Events指定的HTTP请求Flux的情况下。

从另一个终端使用curl命令进行确认。

添加 Accept: text/event-stream 头。
$ curl -v http://localhost:8080/flux-sse -H 'Accept: text/event-stream' -w '\n'
*   Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /flux-sse HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.81.0
> Accept: text/event-stream
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< transfer-encoding: chunked
< Vary: Origin
< Vary: Access-Control-Request-Method
< Vary: Access-Control-Request-Headers
< Content-Type: text/event-stream;charset=UTF-8
<
data:{"message":"Hello Flux 1!"}

data:{"message":"Hello Flux 2!"}

data:{"message":"Hello Flux 3!"}

data:{"message":"Hello Flux 4!"}

data:{"message":"Hello Flux 5!"}

event:end

* Connection #0 to host localhost left intact

我要从另一个终端确认日志文件。※仅摘录了必要的部分。

$ cd ~/tmp/async-spring-webflux/log
$ cat app.log
cat app.log
2023-03-20 12:22:02.249 [INFO ] [main] org.springframework.boot.web.embedded.netty.NettyWebServer.start:111 - Netty started on port 8080
2023-03-20 12:22:02.256 [INFO ] [main] org.springframework.boot.StartupInfoLogger.logStarted:61 - Started Application in 1.035 seconds (JVM running for 1.224)
2023-03-20 12:22:17.814 [INFO ] [parallel-1] com.example.springwebflux.Application.lambda$getFluxWithSSE$4:48 - Sending message: {message=Hello Flux 1!}
2023-03-20 12:22:19.827 [INFO ] [parallel-2] com.example.springwebflux.Application.lambda$getFluxWithSSE$4:48 - Sending message: {message=Hello Flux 2!}
2023-03-20 12:22:21.831 [INFO ] [parallel-3] com.example.springwebflux.Application.lambda$getFluxWithSSE$4:48 - Sending message: {message=Hello Flux 3!}
2023-03-20 12:22:23.842 [INFO ] [parallel-4] com.example.springwebflux.Application.lambda$getFluxWithSSE$4:48 - Sending message: {message=Hello Flux 4!}
2023-03-20 12:22:25.854 [INFO ] [parallel-5] com.example.springwebflux.Application.lambda$getFluxWithSSE$4:48 - Sending message: {message=Hello Flux 5!}
从名为parallel-n的线程中,Spring WebFlux每2秒在并行处理线程中处理Flux。客户端(curl)会以逐个数据的方式实时获取数据。

这是目前为止的总结。

在Spring WebFlux中,我们使用Netty作为内置的Web服务器。 Flux对象被异步处理。

仅提供一种选项:
总结

我能够在使用Ubuntu搭建的简单Java开发环境下,运行实现了Server-Sent Events的Spring WebFlux Web服务。

使用 Ubuntu 会使你掌握 Linux 的知识。刚开始可能会感觉困难,但随着逐渐的学习,你会逐渐有信心并能够自如地操作。

请问感觉怎么样?在 WSL Ubuntu 上,您可以轻松运行实现 Server-Sent Events 的 Spring Boot Web 应用程序。请务必尝试一下。我们将继续介绍Java开发环境等内容,请敬请期待。

请提供相关参考资料。

W3C服务器推送事件

 

HTML 9.2服务器推送事件活动标准

 

MDN 服务器发送事件

 

bannerAds