Как использовать Context с flatMap () в Reactor? - PullRequest
0 голосов
/ 07 февраля 2019

У меня проблема с пониманием Контекст .Поэтому в документации говорится, что Context - это:

Хранилище ключей / значений, которое распространяется между компонентами, такими как операторы, через контекстный протокол.Контексты идеальны для передачи ортогональной информации, такой как маркеры трассировки или безопасности.

Отлично.

Теперь давайте предположим, что мы хотим распространить что-то, используя Context , чтобы иметь этовезде.Для вызова другого асинхронного кода мы просто используем метод flatMap () .

Проблема : Как получить доступ к Context внутри вызываемого метода?

Пример (простой) кода:

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
    }
}

Вызванный метод может быть (и, скорее всего, будет) в другом классе.

Заранее спасибо за помощь!

Редактировать : убран код, чтобы сделать вопрос более кратким и понятным.

1 Ответ

0 голосов
/ 07 февраля 2019

Создайте цепочку Publisher с, и пусть Context будет с вами

В этом случае вы подключили все свои Publisher с (и это включает в себя соединения в пределах flatMap / concatMapи аналогичные операторы) Context будет правильно распространяться по всей среде выполнения потока.

Для доступа к Context в методе nameToGreeting вы можете вызвать Mono.subscribeContext и получить сохраненное информационное событие, если оно кажетсячто методы не связаны.Ниже показана упомянутая концепция:

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 !!!
    }
}

Кроме того, вы можете сделать то же самое следующим образом, используя оператор 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 + " " + "!!!"
        );
    }
}

Итак,почему это работает?

Как видно из примера выше, nameToGreeting вызывается в контексте основного Flux.Под капотом -> (Здесь некоторые внутренние компоненты FluxFlatMap) , каждое сопоставленное Publisher подписано FlatMapInner.Если мы посмотрим на FlatMapInner и ищем currentContext переопределение , мы увидим, что FlatMapInner использует родительский Context, что означает, что у родителя есть ReactorContext - тогда этот контекст будет распространяться на каждый внутренний Publisher.

Следовательно, возвращаемый методом nameToGreeting 1042 * будет иметь тот же Context, что и его родительский

...