Spring-Reactive направлен на обеспечение поддержки реактивного программирования для проектов, основанных на Spring, и ожидается, что это будет доступно в сроки Spring 5 . Мое намерение здесь состоит в том, чтобы использовать некоторые из самых основных сигнатур для конечных точек REST с этой моделью.
Прежде чем я продолжу, позвольте мне признать, что весь этот образец полностью основан на образцах, которые Себастьян Делез собрал здесь — https://github.com/sdeleuze/spring-reactive-playground
Я хотел рассмотреть три примера: во-первых, случай, когда существующее Java 8 CompletableFuture возвращается как тип, во-вторых, когда Observable в RxJava возвращается как тип, и в-третьих, с типом Flux Spring Reactor Core .
Ожидаемый протокол
Структура запроса и ответного сообщения, обрабатываемого каждой из трех служб, соответствует этим направлениям, все они будут принимать запрос, который выглядит следующим образом:
|
1
2
3
4
5
6
|
{ "id":1, "delay_by": 2000, "payload": "Hello", "throw_exception": false} |
Delay_by сделает ответ задержанным, а throw_exception сделает ответ на ошибку. Разумный ответ будет следующим:
|
1
2
3
4
5
|
{ "id": "1", "received": "Hello", "payload": "Response Message"} |
Я буду игнорировать исключения для этого поста.
CompletableFuture как тип возвращаемого значения
Рассмотрим сервис, который возвращает Java CompletableFuture 8 в качестве возвращаемого типа:
|
1
2
3
4
5
6
|
public CompletableFuture<MessageAcknowledgement> handleMessage(Message message) { return CompletableFuture.supplyAsync(() -> { Util.delay(message.getDelayBy()); return new MessageAcknowledgement(message.getId(), message.getPayload(), "data from CompletableFutureService"); }, futureExecutor);} |
Подпись метода Контроллера, который вызывает этот сервис, теперь выглядит следующим образом:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
@RestControllerpublic class CompletableFutureController { private final CompletableFutureService aService; @Autowired public CompletableFutureController(CompletableFutureService aService) { this.aService = aService; } @RequestMapping(path = "/handleMessageFuture", method = RequestMethod.POST) public CompletableFuture<MessageAcknowledgement> handleMessage(@RequestBody Message message) { return this.aService.handleMessage(message); }} |
Когда CompletableFuture завершит каркас, убедитесь, что ответ соответствующим образом перенаправлен обратно.
Rx Java Наблюдаемый как тип возврата
Рассмотрим сервис, который возвращает Rx Java Observable в качестве возвращаемого типа:
|
01
02
03
04
05
06
07
08
09
10
11
|
public Observable<MessageAcknowledgement> handleMessage(Message message) { logger.info("About to Acknowledge"); return Observable.just(message) .delay(message.getDelayBy(), TimeUnit.MILLISECONDS) .flatMap(msg -> { if (msg.isThrowException()) { return Observable.error(new IllegalStateException("Throwing a deliberate exception!")); } return Observable.just(new MessageAcknowledgement(message.getId(), message.getPayload(), "From RxJavaService")); });} |
Контроллер, вызывающий такую службу, теперь может напрямую возвращать Observable как тип, и инфраструктура будет гарантировать, что после того, как все элементы будут отправлены, ответ будет правильно распределен.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
@RestControllerpublic class RxJavaController { private final RxJavaService aService; @Autowired public RxJavaController(RxJavaService aService) { this.aService = aService; } @RequestMapping(path = "/handleMessageRxJava", method = RequestMethod.POST) public Observable<MessageAcknowledgement> handleMessage(@RequestBody Message message) { System.out.println("Got Message.."); return this.aService.handleMessage(message); }} |
Обратите внимание, что поскольку Observable представляет поток от 0 до многих элементов, на этот раз ответом является массив json.
Пружинный реактор Core Flux как тип возврата
Наконец, если тип ответа — тип Flux , структура гарантирует, что ответ обрабатывается аккуратно. Сервис по этим направлениям:
|
01
02
03
04
05
06
07
08
09
10
11
12
|
public Flux<messageacknowledgement> handleMessage(Message message) { return Flux.just(message) .delay(Duration.ofMillis(message.getDelayBy())) .map(msg -> Tuple.of(msg, msg.isThrowException())) .flatMap(tup -> { if (tup.getT2()) { return Flux.error(new IllegalStateException("Throwing a deliberate Exception!")); } Message msg = tup.getT1(); return Flux.just(new MessageAcknowledgement(msg.getId(), msg.getPayload(), "Response from ReactorService")); });} |
и контроллер, использующий такую услугу:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
@RestControllerpublic class ReactorController { private final ReactorService aService; @Autowired public ReactorController(ReactorService aService) { this.aService = aService; } @RequestMapping(path = "/handleMessageReactor", method = RequestMethod.POST) public Flux<MessageAcknowledgement> handleMessage(@RequestBody Message message) { return this.aService.handleMessage(message); }} |
Вывод
Это просто выборка типов возвращаемых данных, поддерживаемых проектом Spring Reactive. Возможные типы возвращаемых значений намного больше этого — вот гораздо более полный пример.
Я с нетерпением жду, когда модель реактивного программирования станет доступной в базовой среде Spring.
Примеры, представленные в этом блоге, доступны в моем репозитории github.
| Ссылка: | Spring-Reactive образцы от нашего партнера JCG Биджу Кунджуммен в блоге all and sundry. |