簡體   English   中英

如果資源是 Mono,我如何在反應器中使用 try-with-resources patter?

[英]How can I use the try-with-resources patter in reactor, if resource is a Mono?

我有一個客戶端,它被創建為 Mono,例如

Mono<MyClient> myClientMono =...

MyClient class 實現Closeable接口,因此您可以使用標准的 java try-with-resources 模式。

使用Mono包裝的資源的最佳方式是什么?

如果資源是常規 object,如InputStream ,我了解如何使用 Mono.using() 來模擬 try-with-resources。

但是,如何確保 myclient 在與 Reactor 一起使用后被關閉?

我可以這樣做:

Mono.using(() -> myClientMono.block(),
        myClient -> myClient.doSomething(),
        myClient.close())
    .subscribe(System.out::println);

但是,這將是阻塞的,不能在異步線程中使用。

我可以做這樣的事情並在使用后關閉客戶端:

myClientMono
  .flatMap( myClient -> { 
        var a = myClient.doSomething();
        myClient.close();
        return Mono.just(a);
     })
  .subscribe(Sytem.out::println);

但是,如果發生錯誤,這不會關閉客戶端。

我想知道是否有更好的解決方案?

正確的解決方案是使用Mono.usingWhenFlux.usingWhen

在這兩種情況下,您都提供了一個資源發布者,每次用戶訂閱時都會調用它來生成新資源。

讓我們看一個例子:

import java.time.Duration;

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

public class UsingWhen {

    /** Simulates a closeable resource. Prints a message when opening and closing. */
    public static class ReactiveResourceMock implements AutoCloseable {

        public ReactiveResourceMock() { System.out.println("OPENING"); }

        Flux<Integer> content() { return Flux.range(1, 3); }

        @Override
        public void close() throws Exception { System.out.println("CLOSING"); };
    }

    /** Simulates async value opening */
    public static Mono<ReactiveResourceMock> open() {
        return Mono.delay(Duration.ofMillis(200))
                   .map(i -> new ReactiveResourceMock());
    }


    public static void main(String[] args) {
        Mono<ReactiveResourceMock> openResource = open();

        Flux<Integer> flow = Flux.usingWhen(
                openResource,
                ReactiveResourceMock::content,
                resource -> Mono.fromCallable(() -> {
                    resource.close();
                    return 1;
                }))
                .doOnCancel(() -> System.out.println("CANCELLED"))
                .doOnComplete(() -> System.out.println("COMPLETED"));

        System.out.println("VERIFY FLOW CONTROL:");
        flow.doOnNext(System.out::println)
            .blockLast();

        System.out.println("WHAT HAPPENS IN CASE OF ERROR:");
        flow.limitRate(1)
            .map(i -> i / (i % 2))
            .onErrorReturn(-1)
            .doOnNext(System.out::println)
            .blockLast();
    }
}

上面的程序打印:

VERIFY FLOW CONTROL:
OPENING
1
2
3
CLOSING
COMPLETED
WHAT HAPPENS IN CASE OF ERROR:
OPENING
1
CANCELLED
-1
CLOSING

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM