Понимание порядка выполнения с помощью .then(Mono{})

Я пытаюсь понять поведение .then(Mono(x)) в Spring WebFlux.

У меня есть следующий код:

fun storeIfValid(x): Mono<Long> =
    doSomeChecksThatMightFail().then(repo.save(x))

Чтение документации then позволяет мне поверить, что блок repo.save(x) выполняется только тогда, когда публикуется сигнал onComplete из предыдущего Mono. В случае сбоя первого Mono я не ожидаю никакого взаимодействия с моим репозиторием.

Я знаю, что могу «исправить» это, используя следующее:

fun storeIfValid(x): Mono<Long> =
    doSomeChecksThatMightFail().flatMap{ repo.save(x) }

или также следующие работы:

fun storeIfValid(x): Mono<Long> =
    doSomeChecksThatMightFail().then(Mono.defer{repo.save(x)})

но я изо всех сил пытаюсь полностью понять, почему. Кажется, что Mono в блоке then уже выполняется до завершения первоначального Mono?

Может быть, кто-то сможет пролить немного света на эту тему... все объяснения, которые я нашел до сих пор (stackoverflow,

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
0
65
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Аргументы, передаваемые при вызове метода, всегда оцениваются до вызова метода. repo.save(x) должен быть оценен (т. е. вызван) до вызова then, поэтому все, что делает then, не повлияет на то, когда будет вызван repo.save(x).

В этом случае then создает новый Mono, который воспроизводит Mono, возвращенный repo.save(x), после завершения Mono, возвращенного doSomeChecksThatMightFail().

Другими словами, x сохраняется немедленно, но Mono, возвращаемый storeIfValid, будет генерировать сохраненный экземпляр (возвращенный repo.save(x)) только после завершения doSomeChecksThatMightFail().

В случаях flatMap и deferrepo.save(x) находится в лямбда-выражении. Когда вычисляется лямбда-выражение, оно просто создает объект, представляющий это лямбда-выражение. Только после вызова лямбда-выражения запускается код лямбда-выражения.

Для flatMap лямбда вызывается, когда doSomeChecksThatMightFail() выдает значение. Для defer лямбда вызывается при воспроизведении Mono, т. е. после завершения doSomeChecksThatMightFail из-за .then(...).


Обратите внимание, что подходы flatMap и defer немного отличаются. flatMap не будет выдавать значение или запускать лямбду, если doSomeChecksThatMightFail завершится без выдачи значения.

Большое спасибо! Я думаю, что самый важный вывод — это первый абзац. Я поставлю .then(Mono.defer { }), так как считаю, что отсутствие выполнения на картах в пустотах часто упускается из виду и может быстро привести к ошибкам.

fjunk 18.07.2024 11:38

Другие вопросы по теме

Похожие вопросы

Изменение часового пояса не приводит к тому, что LocalTime.now() возвращает другое значение, почему?
Может ли один и тот же код, использующий HttpClient, скомпилироваться с Spring-5.x и 6.x?
Улучшите качество подписи, извлеченной с помощью OpenCV из отсканированного листа бумаги
Переверните последовательные нули в единицы за k операций, чтобы получить максимальное количество единиц, найдите максимальное количество единиц
Влияет ли расстояние между операторами, отступами и комментариями в коде на его временную и пространственную сложность?
Почему мой код не удаляет zip-файл, созданный моим модульным тестом?
Приложение Spring Boot не запускается после добавления интеграции с клавиатурой
Исключение в потоке «main» java.time.format.DateTimeParseException: текст «1 апреля 2022 г., 12:00:00:000AM» не удалось проанализировать по индексу 19
Создайте Map<Long, CustomObject> , повторяя List<CustomObject>
Предупреждение о попытке с ресурсами для закрытия Super OutputStream