当前位置: 首页 > 面试题库 >

带有非流应用程序/ json的Spring WebFlux Flux行为

裴韬
2023-03-14
问题内容

我正在评估使用Spring Webflux,但我们必须支持期望使用application / json而不是application / stream +
json的客户端。我不清楚在需要application / json的客户端中,Spring WebFlux如何处理序列化Flux。

如果将Flux序列化为application / json而不是application / stream + json,这是否是阻塞操作?

下面,我整理了一个示例控制器来演示我所看到的。当流是无限的并且产生application /
json时,什么都不会返回到浏览器。这似乎很合理,因为它可能正在等待流终止。当流是无限的并产生application / stream +
json时,我会按预期在浏览器中连续看到JSON对象。当Flux是有限的(例如100个元素)并且类型为application /
json时,它将一次按预期呈现。 问题是,它是否必须等待Flux终止才能进行序列化,是否会导致阻塞操作。 返回正常的application /
json时,使用Flux对性能和可伸缩性有何影响?

@RestController
public class ReactiveController {

    /* Note: In the browser this sits forever and never renders */
    @GetMapping(path = "/nonStreaming", produces = MediaType.APPLICATION_JSON_VALUE)
    public Flux<Person> getPeopleNonStreaming() {
        return Flux.interval(Duration.ofMillis(100))
                .map(tick -> new Person("Dude", "Dude", tick));
    }

    /* Note: This renders in the browser in chunks forever */
    @GetMapping(path = "/streaming", produces = MediaType.APPLICATION_STREAM_JSON_VALUE)
    public Flux<Person> getPeopleStreaming() {
        return Flux.interval(Duration.ofMillis(100))
                .map(tick -> new Person("Dude", "Dude", tick));
    }

    /* Note: This returns, but I can't tell if it is done in a non blocking manner. It
     * appears to gather everything before serializing. */
    @GetMapping(path = "/finiteFlux", produces = MediaType.APPLICATION_JSON_VALUE)
    public Flux<Person> finiteFlux() {
        return Flux.range(0, 100)
                .map(tick -> new Person("Dude", "Dude", tick));
    }
}

更新:

我在下面添加了其他日志记录信息:

流似乎正在使用两个不同的线程

2019-02-13 16:53:07.363 DEBUG 3416 --- [ctor-http-nio-2] o.s.w.s.adapter.HttpWebHandlerAdapter    : [dac80fd4] HTTP GET "/streaming"
2019-02-13 16:53:07.384 DEBUG 3416 --- [ctor-http-nio-2] s.w.r.r.m.a.RequestMappingHandlerMapping : [dac80fd4] Mapped to public reactor.core.publisher.Flux<io.jkratz.reactivedemo.Person> io.jkratz.reactivedemo.ReactiveController.getPeopleStreaming()
2019-02-13 16:53:07.398 DEBUG 3416 --- [ctor-http-nio-2] o.s.w.r.r.m.a.ResponseBodyResultHandler  : Using 'application/stream+json;q=0.8' given [text/html, application/xhtml+xml, image/webp, image/apng, application/xml;q=0.9, */*;q=0.8] and supported [application/stream+json]
2019-02-13 16:53:07.398 DEBUG 3416 --- [ctor-http-nio-2] o.s.w.r.r.m.a.ResponseBodyResultHandler  : [dac80fd4] 0..N [io.jkratz.reactivedemo.Person]
2019-02-13 16:53:07.532 DEBUG 3416 --- [     parallel-1] o.s.http.codec.json.Jackson2JsonEncoder  : [dac80fd4] Encoding [io.jkratz.reactivedemo.Person@6b3e843d]
2019-02-13 16:53:07.566 DEBUG 3416 --- [ctor-http-nio-2] r.n.channel.ChannelOperationsHandler     : [id: 0xdac80fd4, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:52398] Writing object DefaultHttpResponse(decodeResult: success, version: HTTP/1.1)
HTTP/1.1 200 OK
transfer-encoding: chunked
Content-Type: application/stream+json;q=0.8;charset=UTF-8
2019-02-13 16:53:07.591 DEBUG 3416 --- [ctor-http-nio-2] r.n.channel.ChannelOperationsHandler     : [id: 0xdac80fd4, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:52398] Writing object 
2019-02-13 16:53:07.629 DEBUG 3416 --- [     parallel-1] o.s.http.codec.json.Jackson2JsonEncoder  : [dac80fd4] Encoding [io.jkratz.reactivedemo.Person@217d62db]
2019-02-13 16:53:07.630 DEBUG 3416 --- [ctor-http-nio-2] r.n.channel.ChannelOperationsHandler     : [id: 0xdac80fd4, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:52398] Writing object 
2019-02-13 16:53:07.732 DEBUG 3416 --- [     parallel-1] o.s.http.codec.json.Jackson2JsonEncoder  : [dac80fd4] Encoding [io.jkratz.reactivedemo.Person@741c0c88]
2019-02-13 16:53:07.732 DEBUG 3416 --- [ctor-http-nio-2] r.n.channel.ChannelOperationsHandler     : [id: 0xdac80fd4, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:52398] Writing object 
2019-02-13 16:53:07.832 DEBUG 3416 --- [     parallel-1] o.s.http.codec.json.Jackson2JsonEncoder  : [dac80fd4] Encoding [io.jkratz.reactivedemo.Person@7b8532e5]

而使用JSON的有限对象仅使用一个线程。

2019-02-13 16:55:34.431 DEBUG 3416 --- [ctor-http-nio-3] o.s.w.s.adapter.HttpWebHandlerAdapter    : [5b048f46] HTTP GET "/finiteFlux"
2019-02-13 16:55:34.432 DEBUG 3416 --- [ctor-http-nio-3] s.w.r.r.m.a.RequestMappingHandlerMapping : [5b048f46] Mapped to public reactor.core.publisher.Flux<io.jkratz.reactivedemo.Person> io.jkratz.reactivedemo.ReactiveController.finiteFlux()
2019-02-13 16:55:34.434 DEBUG 3416 --- [ctor-http-nio-3] o.s.w.r.r.m.a.ResponseBodyResultHandler  : Using 'application/json;q=0.8' given [text/html, application/xhtml+xml, image/webp, image/apng, application/xml;q=0.9, */*;q=0.8] and supported [application/json]
2019-02-13 16:55:34.435 DEBUG 3416 --- [ctor-http-nio-3] o.s.w.r.r.m.a.ResponseBodyResultHandler  : [5b048f46] 0..N [io.jkratz.reactivedemo.Person]
2019-02-13 16:55:34.439 DEBUG 3416 --- [ctor-http-nio-3] o.s.http.codec.json.Jackson2JsonEncoder  : [5b048f46] Encoding [[io.jkratz.reactivedemo.Person@425c8296, io.jkratz.reactivedemo.Person@22ae73df, io.jkratz.reactived (truncated)...]
2019-02-13 16:55:34.448 DEBUG 3416 --- [ctor-http-nio-3] r.n.channel.ChannelOperationsHandler     : [id: 0x5b048f46, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:52991] Writing object DefaultHttpResponse(decodeResult: success, version: HTTP/1.1)
HTTP/1.1 200 OK
transfer-encoding: chunked
Content-Type: application/json;q=0.8;charset=UTF-8
2019-02-13 16:55:34.448 DEBUG 3416 --- [ctor-http-nio-3] r.n.channel.ChannelOperationsHandler     : [id: 0x5b048f46, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:52991] Writing object 
2019-02-13 16:55:34.450 DEBUG 3416 --- [ctor-http-nio-3] o.s.w.s.adapter.HttpWebHandlerAdapter    : [5b048f46] Completed 200 OK
2019-02-13 16:55:34.450 DEBUG 3416 --- [ctor-http-nio-3] r.n.http.server.HttpServerOperations     : [id: 0x5b048f46, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:52991] Last HTTP response frame
2019-02-13 16:55:34.450 DEBUG 3416 --- [ctor-http-nio-3] r.n.channel.ChannelOperationsHandler     : [id: 0x5b048f46, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:52991] Writing object EmptyLastHttpContent
2019-02-13 16:55:34.450 DEBUG 3416 --- [ctor-http-nio-3] r.n.http.server.HttpServerOperations     : [id: 0x5b048f46, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:52991] Decreasing pending responses, now 0
2019-02-13 16:55:34.451 DEBUG 3416 --- [ctor-http-nio-3] r.n.channel.ChannelOperationsHandler     : [id: 0x5b048f46, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:52991] No ChannelOperation attached. Dropping: EmptyLastHttpContent

问题答案:

对于流式mimetype(application/stream+json),Spring
WebFlux中默认配置的JSON编解码器将序列化为JSON,并在网络上刷新Flux输入的每个元素。当流无限或要在可用时将信息推送到客户端时,此行为很方便。请注意,这会降低性能,因为调用串行器并多次刷新会占用资源。

对于非流类型(application/json),在Spring
WebFlux中默认配置的JSON编解码器将序列化为JSON并一次性刷新到网络。它将缓存Flux<YourObject>在内存中,并在一次通过中将其序列化。这并不意味着操作正在阻塞,因为结果Flux<Databuffer>是以反应方式写入网络的。这里没有任何障碍。

这只是“流数据和使用更多资源”与“缓冲和更有效地使用资源”之间的折衷。

在流传输的情况下,由于工作项在不同的时间间隔可用,因此更有可能由不同的工作线程处理事物。对于简单的JSON响应-
也可能由一个或多个线程处理:无论远程客户端是否慢,它都取决于有效负载大小。



 类似资料:
  • 我正在评估使用Spring Webflux,但我们必须支持期望Application/JSON,而不是Application/Stream+JSON的客户机。我不清楚Spring WebFlux如何在需要Application/JSON的客户机的情况下处理Flux的序列化。 如果一个Flux序列化为application/json,而不是application/stream+json,这是一个阻塞

  • 问题内容: 我需要从Docker容器中在后台运行的Java应用程序中启动Selenium。启动失败,因为在运行时无法访问X11环境。请参阅下面的内容。 我该怎么办? 问题 我从安装Java 8和Jetty 9.3.x 的简单程序开始运行一个简单的服务(实际上是selenium的东西)。该服务实际上是为了启动一些需要UI才能执行的事情而设置的。我遇到的问题是其中的任何内容执行失败,因为UI在我运行的

  • 下图说明数据流如何贯穿整个系统: index.php 作为前端控制器,初始化运行 CodeIgniter 所需要的基本资源。 Router 检查 HTTP 请求,以确定谁来处理请求。 如果缓存(Cache)文件存在,它将绕过通常的系统执行顺序,被直接发送给浏览器。 安全(Security)。应用程序控制器(Application Controller)装载之前,HTTP 请求和任何用户提交的数据将

  • 问题内容: {新手Android开发人员} 我目前正在使用在Github上找到的Google的开源媒体应用来尝试为自己的项目之一创建自己的媒体播放器。但是,我一直遇到的一个问题是,当我从以下位置更改RemoteJSON中的JSON文件时: 至 (使用myjson.com存储文件) 它会填充应用程序内的信息,但是当选择一项时,会产生MediaPlayer错误1(-2147483648)。(我所做的只

  • 我有一个简单的Spring-Boot应用程序,它只使用AMQP依赖项(仅-例如,没有web依赖项,所以JAR中没有包含应用服务器)。 我只想让应用程序运行并监听队列,并在收到消息时将一些信息记录到DB中--然而,由于没有应用程序服务器,它一启动就会再次关闭(因为什么都没有做)。在监听消息的同时,是否有一种最好的方法来保持应用程序的运行? 代码中没有什么令人惊讶的地方,只是标准的应用程序配置,然后还

  • 我一直在努力让我的第一个Android应用程序工作。我有一个使用webview的活动,我用它来打开上面有html表单的网页。 让“选择文件”按钮(用于文件输入)工作有些困难,但多亏了这里发布的在网络视图中上传文件的帮助,我终于解决了这个问题。从那里,我基本上使用了他们在Github上提供的主活动java代码。 我的实际问题是,当点击一个文件输入按钮时,我没有让用户使用我想要的设备摄像头的选项。起初