简体   繁体   English

如何在 Reactor 中将 Context 与 flatMap() 一起使用?

[英]How to use Context with flatMap() in Reactor?

I have a problem understanding Context .我在理解Context 时遇到问题。 So documentations says that Context is:所以文档说Context是:

A key/value store that is propagated between components such as operators via the context protocol.通过上下文协议在运算符等组件之间传播的键/值存储。 Contexts are ideal to transport orthogonal information such as tracing or security tokens.上下文非常适合传输正交信息,例如跟踪或安全令牌。

Great.伟大的。

Now let's suppose we want to propagate something using Context to have it everywhere.现在让我们假设我们想使用Context传播一些东西,让它无处不在。 To call another async code we simply use the flatMap() method.要调用另一个异步代码,我们只需使用flatMap()方法。

Problem : how to access Context inside called method?问题如何访问被调用方法内的上下文?

Sample (simple) code:示例(简单)代码:

public class TestFlatMap {
    public static void main(final String ...args) {
        final Flux<String> greetings = Flux.just("Hubert", "Sharon")
            .flatMap(TestFlatMap::nameToGreeting)
            .subscriberContext(context ->
                Context.of("greetingWord", "Hello")  // context initialized
            );
        greetings.subscribe(System.out::println);
    }

    private static Mono<String> nameToGreeting(final String name) {
        return Mono.just("Hello " + name + " !!!");  // ALERT: we don't have Context here
    }
}

The called method can be (and most likely will be) in another class.被调用的方法可以(并且很可能会)在另一个类中。

Thanks for help in advance !提前感谢您的帮助!

Edit : removed some code to make the question more concise and straight to the point.编辑:删除了一些代码,使问题更加简洁明了。

Chain your Publisher s and may the Context be with you 链接您的Publisher ,并且Context可能与您同在

In the case, you connected all your Publisher s (and this includes connections within the flatMap / concatMap and similar operators) you will have Context correctly propagated among the whole stream runtime. 在这种情况下,您连接了所有Publisher (并且这包括flatMap / concatMap和类似运算符中的连接),您将在整个流运行时之间正确传播Context

To access Context in the nameToGreeting method, you may call Mono.subscribeContext and retrieve stored info event if it seems that methods are not related. 要在nameToGreeting方法中访问Context ,您可以调用Mono.subscribeContext并检索存储的信息事件(如果方法似乎不相关)。 The following shows the mentioned concept: 以下显示了上述概念:

public class TestFlatMap {
    public static void main(final String ...args) {
        final Flux<String> greetings = Flux.just("Hubert", "Sharon")
                                           .flatMap(TestFlatMap::nameToGreeting)
                                           .subscriberContext(context ->
                                                   Context.of("greetingWord", "Hello")  // context initialized
                                           );
        greetings.subscribe(System.out::println);
    }

    private static Mono<String> nameToGreeting(final String name) {
        return Mono.subscriberContext()
                   .filter(c -> c.hasKey("greetingWord"))
                   .map(c -> c.get("greetingWord"))
                   .flatMap(greetingWord -> Mono.just(greetingWord + " " + name + " " + "!!!"));// ALERT: we have Context here !!!
    }
}

Also, you can do the same in the following way, using zip operator, to combine results later: 此外,您可以使用zip运算符以下列方式执行相同操作,以便稍后合并结果:

public class TestFlatMap {
    public static void main(final String ...args) {
        final Flux<String> greetings = Flux.just("Hubert", "Sharon")
                                           .flatMap(TestFlatMap::nameToGreeting)
                                           .subscriberContext(context ->
                                                   Context.of("greetingWord", "Hello")  // context initialized
                                           );
        greetings.subscribe(System.out::println);
    }

    private static Mono<String> nameToGreeting(final String name) {
        return Mono.zip(
            Mono.subscriberContext()
                .filter(c -> c.hasKey("greetingWord"))
                .map(c -> c.get("greetingWord")), // ALERT: we have Context here !!!
            Mono.just(name),
            (greetingWord, receivedName) -> greetingWord + " " + receivedName + " " + "!!!"
        );
    }
}

So, why it works? 那么,为什么它有效呢?

As we can see from the sample above, the nameToGreeting is called within the context of the main Flux . 从上面的示例中可以看出, nameToGreeting是在主要Flux的上下文中调用的。 Under the hood -> (Here Some FluxFlatMap internals) , each mapped Publisher is subscribed by FlatMapInner . 在引擎盖下 - > (这里有一些FluxFlatMap内部) ,每个映射的Publisher都由FlatMapInner订阅。 If we look at the FlatMapInner and look for the currentContext override we will see, that FlatMapInner uses parent Context , which means if the parent has a Reactor Context - then this context will be propagated to each inner Publisher . 如果我们查看FlatMapInner并查找currentContext重写,我们将看到, FlatMapInner使用父Context ,这意味着如果父有一个Reactor Context - 那么这个上下文将传播到每个内部Publisher

Therefore, returned by the nameToGreeting method Mono will have the same Context as its parent 因此,由nameToGreeting方法返回的Mono将具有与其父级相同的Context

Reactor-Core v3.4 introduced Mono.deferContextual and Flux.deferContextual , which supersede Mono.deferWithContext and Flux.deferWithContext introduced in v3.3. Reactor-Core v3.4 引入了Mono.deferContextualFlux.deferContextual ,它们取代了 v3.3 中引入的Mono.deferWithContextFlux.deferWithContext

Using these methods, Oleh Dokukas zip example can be simplified to使用这些方法, Oleh Dokukas zip 示例可以简化为

public class TestFlatMap {
    public static void main(final String ...args) {
        final Flux<String> greetings = Flux.just("Hubert", "Sharon")
                .flatMap(TestFlatMap::nameToGreeting)
                .subscriberContext(context ->
                        Context.of("greetingWord", "Hello"));  // context initialized
        greetings.subscribe(System.out::println);
    }

    private static Mono<String> nameToGreeting(final String name) {
        return Mono.deferContextual(c -> Mono.just(name)
                .filter(x -> c.hasKey("greetingWord"))
                .map(n -> c.get("greetingWord") + " " + n + " " + "!!!"));
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM