#java #spring #spring-boot #reactive-programming #spring-webflux
Вопрос:
Недавно я начал работать над приложением Spring Webflux с использованием реактивных потоков. У меня есть 2 вопроса.
- В чем разница между
void
иMono<Void>
- У меня есть пример использования, подобный следующему, где, по моему мнению, можно было бы улучшить с помощью
void
илиMono<Void>
@Service public class ABCService { public Mono<String> getGreeting(String name) { Mono.just(NameValidator.validate(name)) .map(isValid -> "Hello, " name ". Welcome!"); } } public class NameValidator { public static boolean validate(String name) { if(StringUtils.isEmpty(name)) {throw new RuntimeException("Invalid name");} return true; } }
На самом деле мне не нужен метод validate (), чтобы иметь логический тип возвращаемого значения. Это могло бы быть void/Mono<Void>
вместо этого. Я возвращаюсь только true
к выполнению цепочки в ABCService. Может ли кто-нибудь объяснить, как сделать то же самое с помощью void
и Mono<Void>
Комментарии:
1.
Mono.fromRunnable(() -> NameValidator.validate(name)).thenReturn("Hello, " name ". Welcome!")
— это был бы идиоматический способ выполнить это2. Что делать, если я хочу использовать валидатор в середине реактивного конвейера? Что-то вроде этого,
Mono.just(name) .map(n -> n.toUpperCase()) .map(name -> { NameValidator.validate(name); return name; }) .map(name -> "Hello, " name ". Welcome!");
Я знаю, что это надуманный пример, но у меня похожий случай использования3. Я бы использовал его внутри doOnNext, а не на карте.
4. У меня есть 2 вопроса, 1. Когда вы хотели бы вызвать doOnNext ()? 2. Зависит ли это от того, где я его размещаю? Будет ли это действовать по-другому, если я помещу doOnNext() в качестве последнего метода() ПО сравнению с тем, если я использую между этими картами? Что делать, если я хочу, чтобы он был вызван именно в том месте, где я выполняю проверку, т. Е. после 2-й карты в приведенном выше примере.
5. Операторы выполняются в порядке объявления, поэтому имеет значение их место.
Ответ №1:
Если вы вернете Mono, вы не сможете его использовать map()
. Я имею в виду, что вы можете использовать его, но так Mono<Void>
как он никогда не будет выдавать значение, а только сигнал завершения, ваш map()
никогда не вступит в силу. Вам нужно будет заменить его на then()
:
@Service
public class ABCService {
public Mono<String> getGreeting(String name) {
NameValidator.validate(name)
.then(Mono.just("Hello, " name ". Welcome!"));
}
}
Комментарии:
1. Что делать, если я хочу использовать валидатор для уже существующей реактивной цепочки? Что-то вроде этого,
Mono.just(name).map(n -> n.toUpperCase()).map(name -> { NameValidator.validate(name); return name; }).map(name -> "Hello, " name ". Welcome!");
2. Это тоже сработало бы, но, честно говоря, это могло бы быть намного проще. На самом деле вам не нужно Моно от начала до конца. Нет никакой цели в создании Моно только ради его создания, если вы не можете воспользоваться этим преимуществом. В вашем примере я сомневаюсь, что это полезно.
3. Я новичок в webflux. Можете ли вы предложить/показать реальный способ выполнения приведенного выше примера в моем комментарии (
Mono.just(name).map(n -> n.toUpperCase()).....
) Пример немного надуман, но у меня есть похожая вещь, которую я делал в своей работе, где я получаю неname
в нижней части конвейера, а скорее объект, который был получен из другого объекта над ним.4. Что вы хотите сделать с именем, прежде чем проверять его? Преобразовать его только в верхний регистр? Является ли имя простой строкой (не Моно строки)?
5. Для простоты давайте предположим, что я только конвертирую в верхний регистр, прежде чем проверять его. Это может быть и что-то другое, а не
toUpperCase()
другой метод, который должен быть выполнен наверняка. Да,name
это веревочка.Mono.just()
даст намMono<String>
.