reactor Mono

在Java中引入reactor包的目的是为了实现响应式编程。Reactor是一个用于构建非阻塞应用的库,它提供了Flux和Mono两种主要的异步序列类型,可以处理数据流和事件。通过使用Reactor,可以更高效地管理并发和I/O操作,从而提高应用的性能和响应速度。

Flux和Mono是Reactor库中两种主要的异步序列类型。它们的用法如下:

Flux和Mono的区别

Flux和Mono都是Reactor库中的核心类型,用于处理异步数据流,但它们有一些关键的区别:

  1. 元素数量
    • Flux:Flux可以表示0到N个元素的异步序列,适用于需要处理多个元素的场景。
    • Mono:Mono则表示0到1个元素的异步序列,适用于处理单个元素或可能为空的结果。
  2. 用途
    • Flux:适用于需要处理数据流、事件流或批量数据的场景。例如,处理来自数据库的多条记录、处理消息队列中的消息等。
    • Mono:更适合用于单个结果的场景,例如从数据库中查询单条记录、调用返回单个结果的HTTP API等。
  3. 操作符
    • Flux:提供了丰富的操作符来处理多个元素,如filtermapflatMap等。
    • Mono:操作符相对较少,因为它只处理一个元素,但仍提供了一些常用的操作符,如mapflatMap等。

总的来说,Flux和Mono都是强大的工具,用于不同的异步编程场景。选择使用Flux还是Mono,取决于你需要处理的数据序列的元素数量和具体应用场景。

Flux的API及其使用

Reactor库中的Flux提供了许多强大的API,用于处理多个元素的异步序列。以下是一些常用的Flux API及其使用示例:

  1. 创建Flux

    // 创建包含多个元素的Flux
    Flux<String> flux = Flux.just("a", "b", "c");
    
    // 从集合创建Flux
    List<String> list = Arrays.asList("a", "b", "c");
    Flux<String> fluxFromList = Flux.fromIterable(list);
    
    // 创建一个空的Flux
    Flux<String> emptyFlux = Flux.empty();
    
    
  2. 转换和过滤数据

    Flux<Integer> numbers = Flux.range(1, 10);
    
    // 使用map转换元素
    Flux<String> stringNumbers = numbers.map(String::valueOf);
    
    // 使用filter过滤元素
    Flux<Integer> evenNumbers = numbers.filter(num -> num % 2 == 0);
    
    
  3. 组合多个Flux

    Flux<String> flux1 = Flux.just("a", "b", "c");
    Flux<String> flux2 = Flux.just("d", "e", "f");
    
    // 合并两个Flux
    Flux<String> mergedFlux = flux1.mergeWith(flux2);
    
    // 连接两个Flux
    Flux<String> concatenatedFlux = Flux.concat(flux1, flux2);
    
    
  4. 处理错误

    Flux<String> fluxWithError = Flux.just("a", "b")
                                     .concatWith(Flux.error(new RuntimeException("An error occurred")))
                                     .concatWith(Flux.just("c"));
    
    // 使用onErrorResume处理错误并返回一个新的Flux
    Flux<String> fluxWithErrorHandling = fluxWithError.onErrorResume(e -> {
        System.err.println("Error: " + e);
        return Flux.just("default");
    });
    
    
  5. 订阅

    Flux<String> flux = Flux.just("a", "b", "c");
    
    // 订阅Flux并处理每个元素
    flux.subscribe(
        System.out::println,               // 处理每个元素
        error -> System.err.println(error), // 处理错误
        () -> System.out.println("Done")    // 完成时的回调
    );
    
    

上述示例展示了Flux常用API的使用方法。通过这些API,开发者可以方便地处理多个元素的异步序列,实现复杂的数据处理逻辑。

Mono的API及其使用

Reactor库中的Mono提供了一些强大的API,用于处理单个元素或可能为空的异步序列。以下是一些常用的Mono API及其使用示例:

  1. 创建Mono

    // 创建包含单个元素的Mono
    Mono<String> mono = Mono.just("hello");
    
    // 创建一个空的Mono
    Mono<String> emptyMono = Mono.empty();
    
    // 从Callable创建Mono
    Mono<String> callableMono = Mono.fromCallable(() -> "callable result");
    
    
  2. 转换数据

    Mono<Integer> mono = Mono.just(1);
    
    // 使用map转换元素
    Mono<String> stringMono = mono.map(String::valueOf);
    
    // 使用flatMap转换元素并返回新的Mono
    Mono<String> flatMappedMono = mono.flatMap(num -> Mono.just("number: " + num));
    
    
  3. 处理错误

    Mono<String> monoWithError = Mono.error(new RuntimeException("An error occurred"));
    
    // 使用onErrorResume处理错误并返回一个新的Mono
    Mono<String> monoWithErrorHandling = monoWithError.onErrorResume(e -> {
        System.err.println("Error: " + e);
        return Mono.just("default");
    });
    
    // 使用onErrorReturn返回一个默认值
    Mono<String> monoWithDefaultValue = monoWithError.onErrorReturn("default value");
    
    
  4. 订阅

    Mono<String> mono = Mono.just("hello");
    
    // 订阅Mono并处理元素
    mono.subscribe(
        System.out::println,               // 处理元素
        error -> System.err.println(error), // 处理错误
        () -> System.out.println("Done")    // 完成时的回调
    );
    
    
  5. 组合多个Mono

    Mono<String> mono1 = Mono.just("hello");
    Mono<String> mono2 = Mono.just("world");
    
    // 组合两个Mono并返回一个新的Mono
    Mono<String> combinedMono = Mono.zip(mono1, mono2, (str1, str2) -> str1 + " " + str2);
    
    

上述示例展示了Mono常用API的使用方法。通过这些API,开发者可以方便地处理单个元素或可能为空的异步序列,实现简单但灵活的数据处理逻辑。

异步序列指的是数据或事件在不同时间点发生和处理的序列,而不是按顺序同步执行。在计算机编程中,异步序列允许程序在等待一个操作完成(如I/O操作、网络请求)时,不会阻塞主线程,从而提高应用的效率和响应速度。通过异步编程,可以更好地管理并发操作,使系统在处理大量任务时更加高效和灵活。

return Mono.just(route).doOnNext(this::validateRouteDefinition)
				.flatMap(routeDefinition -> this.routeDefinitionWriter.save(Mono.just(routeDefinition).map(r -> {
					r.setId(id);
					log.debug("Saving route: " + route);
					return r;
				})).then(Mono.defer(() -> Mono.just(ResponseEntity.created(URI.create("/routes/" + id)).build()))))
				.switchIfEmpty(Mono.defer(() -> Mono.just(ResponseEntity.badRequest().build())));

这段代码使用了Reactor库中的Mono来处理异步序列。它的主要功能是保存一个路由定义,并在成功或失败时返回相应的HTTP响应。下面是对这段代码的详细解释:

return Mono.just(route)
    .doOnNext(this::validateRouteDefinition)
    .flatMap(routeDefinition -> this.routeDefinitionWriter.save(Mono.just(routeDefinition).map(r -> {
        r.setId(id);
        log.debug("Saving route: " + route);
        return r;
    }))
    .then(Mono.defer(() -> Mono.just(ResponseEntity.created(URI.create("/routes/" + id)).build()))))
    .switchIfEmpty(Mono.defer(() -> Mono.just(ResponseEntity.badRequest().build())));

  1. Mono.just(route): 创建一个包含route的Mono对象,这是一个单元素异步序列。
  2. .doOnNext(this::validateRouteDefinition): 在处理route之前,执行validateRouteDefinition方法对其进行验证。doOnNext用于在每个元素被处理时执行一个回调函数。
  3. .flatMap(routeDefinition -> this.routeDefinitionWriter.save(Mono.just(routeDefinition).map(r -> { ... }))): 使用flatMaprouteDefinition转换为一个新的Mono序列,并调用routeDefinitionWriter.save方法保存路由定义。
    • Mono.just(routeDefinition).map(r -> { ... }): 创建一个包含routeDefinition的Mono,并使用map操作符对其进行转换。
    • r.setId(id): 设置路由定义的ID。
    • log.debug("Saving route: " + route): 记录调试信息。
    • return r: 返回转换后的路由定义。
  4. .then(Mono.defer(() -> Mono.just(ResponseEntity.created(URI.create("/routes/" + id)).build()))): 在保存操作成功后,返回一个包含201 Created响应的Mono对象。
    • Mono.defer(() -> Mono.just(ResponseEntity.created(URI.create("/routes/" + id)).build())): 使用Mono.defer来延迟创建响应对象,确保在保存操作完成后执行。
  5. .switchIfEmpty(Mono.defer(() -> Mono.just(ResponseEntity.badRequest().build()))): 如果输入的route为空,则返回400 Bad Request响应的Mono对象。
    • Mono.defer(() -> Mono.just(ResponseEntity.badRequest().build())): 使用Mono.defer来延迟创建响应对象,确保在输入为空时执行。

总的来说,这段代码的主要流程是:

  1. 验证输入的路由定义。
  2. 保存路由定义,并设置其ID。
  3. 如果保存成功,返回201 Created的HTTP响应。
  4. 如果输入为空,返回400 Bad Request的HTTP响应。

你提到的代码虽然涉及异步操作,但这并不意味着它的执行顺序与同步操作一样。让我们更详细地解释一下异步操作中的执行顺序。

异步操作的核心在于它们不会阻塞调用线程,但它们仍然有执行顺序。下面是对异步执行顺序的详细解释:

public Mono<String> asynchronousQuery(String query) {
    return Mono.fromCallable(() -> database.executeQuery(query)) // 1. 异步查询
               .map(this::processResult) // 2. 处理查询结果
               .onErrorResume(e -> { // 3. 处理错误
                   e.printStackTrace();
                   return Mono.empty();
               });
}

异步执行顺序:

  1. 创建Mono对象:调用Mono.fromCallable,它不会立即执行database.executeQuery(query),而是创建一个Mono对象,代表一个将来会执行的异步操作。

  2. 订阅Mono:当你对这个Mono对象进行订阅时,Mono的操作才会实际执行。订阅的动作通常是由调用者发起的,例如:

    asynchronousQuery("select * from table").subscribe(
        result -> System.out.println("Result: " + result),
        error -> System.err.println("Error: " + error),
        () -> System.out.println("Completed")
    );
    
    
  3. 执行异步查询:在订阅之后,Mono开始执行fromCallable中的代码,即database.executeQuery(query)。这个操作是异步的,它不会阻塞当前线程。

  4. 处理查询结果:当数据库查询完成并返回结果后,Mono会调用map操作符中的this::processResult方法来处理查询结果。

  5. 处理错误:如果在查询或处理结果的过程中发生任何错误,Mono会调用onErrorResume中的错误处理逻辑来处理异常。

实际执行顺序:

  • 订阅前:所有定义的操作都只是描述了将来要做什么,并没有实际执行。
  • 订阅时:从fromCallable开始,描述的操作会按顺序执行,但它们是异步的,不会阻塞主线程。
  • 异步执行:数据库查询在后台线程中执行,查询结果或错误通过回调函数处理。

因此,虽然代码看起来是按顺序写的,但由于Mono的异步特性,实际的执行是异步的,不会阻塞主线程。执行顺序依然是按照定义的逻辑顺序,但操作本身是异步进行的。

总结来说,代码的执行顺序在逻辑上是按顺序的,但实际执行是异步的,不会阻塞主线程。只有在Mono被订阅时,异步操作才会开始执行,并且处理结果或错误。

通过这些示例,希望能帮助你更好地理解Flux和Mono的使用及其区别。

	@PostMapping("/routes/{id}")
	public Mono<ResponseEntity<Object>> save(@PathVariable String id, @RequestBody RouteDefinition route) {

		return Mono.just(route).doOnNext(this::validateRouteDefinition)
				.flatMap(routeDefinition -> this.routeDefinitionWriter.save(Mono.just(routeDefinition).map(r -> {
					r.setId(id);
					log.debug("Saving route: " + route);
					return r;
				})).then(Mono.defer(() -> Mono.just(ResponseEntity.created(URI.create("/routes/" + id)).build()))))
				.switchIfEmpty(Mono.defer(() -> Mono.just(ResponseEntity.badRequest().build())));
	}

是的,这段代码将一个Mono对象返回给浏览器。具体来说,这段代码使用了Reactor库中的Mono来处理异步操作,并返回一个包含HTTP响应的Mono对象。返回的Mono对象表示异步操作的结果,当操作完成时,浏览器将接收到相应的HTTP响应。

当浏览器收到Mono对象后,实际并不会直接处理Mono对象。Mono对象是服务器端用于处理异步操作的工具,浏览器并不会直接接触到它。在服务器端,Mono会异步地执行操作,并在操作完成后生成一个HTTP响应。这个响应会被返回给浏览器,浏览器接收到的实际上是这个HTTP响应,而不是Mono对象本身。

具体来说,Mono对象在服务器端执行以下步骤:

  1. 异步处理逻辑:Mono会在服务器端异步执行定义的逻辑,例如数据库查询、调用外部API等。
  2. 生成响应:根据处理结果,Mono会生成一个HTTP响应对象,例如成功时的201 Created或失败时的400 Bad Request。
  3. 返回响应:生成的HTTP响应会被发送回浏览器。

最终,浏览器接收到的是服务器端处理完毕后返回的HTTP响应,而不是Mono对象。因此,浏览器的行为与接收到普通的HTTP响应时没有区别,浏览器会根据响应的内容进行相应的处理,例如渲染页面、显示消息等。

在Spring WebFlux中,Mono对象的订阅是由WebFlux框架自动完成的。具体来说,当一个请求到达控制器方法并返回一个Mono对象时,Spring WebFlux会自动订阅这个Mono对象,并在其完成时生成并发送HTTP响应。

因此,在控制器方法中返回Mono对象时,不需要手动订阅它。框架会负责订阅和处理Mono对象的整个生命周期,包括执行异步操作、处理结果或错误,以及生成最终的HTTP响应。

这种机制使得开发者可以专注于定义异步逻辑,而不必担心订阅和执行的问题。框架会在适当的时间点自动完成这些操作。

总的来说,Spring WebFlux会负责订阅控制器方法返回的Mono对象,并在其完成时生成并发送相应的HTTP响应。

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值