通過Spring Boot Webflux實現Reactor Kafka
在Apache Kafka簡介中,我們研究了分散式流媒體平臺Apache Kafka。這一次,我們將關注Reactor Kafka,這個庫可以建立從Project Reactor到Kafka Topics的Reactive Streams,反之亦然。
我們將使用兩個小型示例應用程式,Paymentprocessor Gateway和PaymentValidator。這些應用程式的程式碼可以在這裡找到。
Paymentprocessor閘道器提供了一個小網頁,可以生成一個隨機的信用卡號碼(顯然是偽造的),以及支付金額。當使用者單擊提交按鈕時,表單將提交給閘道器的API。API具有針對Kafka群集上的未確認事務主題的反應流,這個未確認事務的主題的另外一邊消費者是PaymentValidator,監聽要驗證的傳入訊息。然後,這些訊息通過響應管道,驗證方法將其列印到命令列。
通過Reactive Streams向Kafka傳送訊息
我們的應用程式構建在Spring 5和Spring Boot 2之上,使我們能夠快速設定和使用Project Reactor。
Gateway應用程式的目標是設定從Web控制器到Kafka叢集的Reactive流。這意味著我們需要特定的依賴關係來彈簧webflux和reactor-kafka。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> <dependency> <groupId>io.projectreactor.kafka</groupId> <artifactId>reactor-kafka</artifactId> <version>1.1.0.RELEASE</version> </dependency> |
Spring Webflux RestController提供支付API,為paymentGateway類的doPayment方法建立一個Reactive流。
/ ** *呼叫返回的Mono將被髮送到Spring Webflux,後者依賴於multi-reactor 事件迴圈和NIO *以非阻塞方式處理請求,從而實現更多的併發請求。結果將 通過一個名為Server Sent Events 傳送。 ** / @PostMapping(value = "/payment") public Mono<Void> doPayment(@RequestBody CreatePaymentCommand payment) { / ** 當呼叫doPayment方法時,我們傳送付款資訊,獲得Mono <Void>作為響應。 當我們的付款成功傳送事件到Kafka主題 ** / return paymentGateway.doPayment(payment); } |
paymentGateway需要一個kafkaProducer,它使我們能夠將訊息作為管道的一部分放在Kafka主題中。它可以使用KafkaSender.create方法輕鬆建立,傳遞許多生產者選項。
public PaymentGatewayImpl() { final Map<String, Object> producerProps = new HashMap<>(); producerProps.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, IntegerSerializer.class); producerProps.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class); producerProps.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092"); final SenderOptions<Integer, String> producerOptions = SenderOptions.create(producerProps); kafkaProducer = KafkaSender.create(producerOptions); } |
建立之後,kafkaProducer可以用來輕鬆地將我們的訊息傳送到選擇的Kafka主題,成為控制器中啟動的管道的一部分。因為訊息是以非阻塞方式傳送到Kafka叢集的,所以我們可以使用專案Reactor的事件迴圈接收並將來自Web API的大量併發訊息路由到Kafka。
@Override public Mono<Void> doPayment(final CreatePaymentCommand createPayment) { final PaymentEvent payment = new PaymentEvent(createPayment.getId(), createPayment.getCreditCardNumber(), createPayment.getAmount(), gatewayName); String payload = toBinary(payment); SenderRecord<Integer, String, Integer> message = SenderRecord.create(new ProducerRecord<>("unconfirmed-transactions", payload), 1); return kafkaProducer.send(Mono.just(message)).next(); } private String toBinary(Object object) { try { return objectMapper.writeValueAsString(object); } catch (JsonProcessingException e) { throw new IllegalArgumentException(e); } } |
從Kafka主題建立反應流
當沒有消費者監聽時,向主題傳送訊息沒有多大意義,因此我們的第二個應用程式將使用一個反應管道來監聽未確認的事務主題。為此,使用KafkaReceiver.create方法建立kafkaReceiver物件,類似於我們之前建立kafkaProducer的方法。
通過使用kafkaReceiver.receive方法,我們可以獲得receiverRecords的Flux。進入我們讀取的主題中每條訊息都放入receiverRecord中。流入應用程式後,它們會進一步通過反應管道。然後,這些訊息傳遞processEvent方法,該方法呼叫paymentValidator,該方法將一些資訊輸出到控制檯。最後,在receiverOffset上呼叫acknowledge方法,向Kafka叢集傳送一條訊息已被處理的確認。
public PaymentValidatorListenerImpl(PaymentValidator paymentValidator) { this.paymentValidator = paymentValidator; final Map<String, Object> consumerProps = new HashMap<>(); consumerProps.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, IntegerDeserializer.class); consumerProps.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); consumerProps.put(ConsumerConfig.CLIENT_ID_CONFIG, "payment-validator-1"); consumerProps.put(ConsumerConfig.GROUP_ID_CONFIG, "payment-validator"); consumerProps.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092"); ReceiverOptions<Object, Object> consumerOptions = ReceiverOptions.create(consumerProps) .subscription(Collections.singleton("unconfirmed-transactions")) .addAssignListener(partitions -> log.debug("onPartitionsAssigned {}", partitions)) .addRevokeListener(partitions -> log.debug("onPartitionsRevoked {}", partitions)); kafkaReceiver = KafkaReceiver.create(consumerOptions); /** * We create a receiver for new unconfirmed transactions */ ((Flux<ReceiverRecord>) kafkaReceiver.receive()) .doOnNext(r -> { /** * Each unconfirmed payment we receive, we convert to a PaymentEvent and process it */ final PaymentEvent paymentEvent = fromBinary((String) r.value(), PaymentEvent.class); processEvent(paymentEvent); r.receiverOffset().acknowledge(); }) .subscribe(); } private void processEvent(PaymentEvent paymentEvent) { paymentValidator.calculateResult(paymentEvent); } private <T> T fromBinary(String object, Class<T> resultType) { try { return objectMapper.readValue(object, resultType); } catch (IOException e) { throw new IllegalArgumentException(e); } } |
可以在此處找到此示例的程式碼
相關文章
- Spring boot webflux 中實現 RequestContextHolderSpring BootWebUXContext
- Spring Boot 通過CORS實現跨域Spring BootCORS跨域
- 使用Spring Boot和Kafka Streams實現CQRSSpring BootKafka
- Spring Boot Reactor Netty配置 | BaeldungSpring BootReactNetty
- Java程式設計方法論-Spring WebFlux篇 Reactor-Netty下TcpServer的功能實現 1Java程式設計SpringWebUXReactNettyTCPServer
- Spring Boot KafkaSpring BootKafka
- Spring Boot WebFlux 增刪改查完整實戰 demoSpring BootWebUX
- Spring Boot 整合 KafkaSpring BootKafka
- 在Spring Boot中實現WebSocket實時通訊Spring BootWeb
- Spring Boot 2.0 WebFlux 教程 (一) | 入門篇Spring BootWebUX
- Spring生態系統中的Reactor、WebFlux和RSocket區別? - FranciscoSpringReactWebUX
- Spring WebFlux效能真的超過Spring Servlet ? - GavinSpringWebUXServlet
- Reactor 第十一篇 WebFlux整合RedisReactWebUXRedis
- 實戰Spring Boot 2.0 Reactive程式設計系列 - WebFlux初體驗Spring BootReact程式設計WebUX
- Spring中通過Annotation來實現AOPSpring
- Spring Boot的Kafka入門Spring BootKafka
- Reactive Spring實戰 -- 理解Reactor的設計與實現ReactSpring
- Spring Boot 2 Webflux的全域性異常處理Spring BootWebUX
- Spring Boot 2 (十):Spring Boot 中的響應式程式設計和 WebFlux 入門Spring Boot程式設計WebUX
- 使用Spring Boot + Kafka實現Saga分散式事務模式的原始碼 - vinsguruSpring BootKafka分散式模式原始碼
- Java程式設計方法論-Spring WebFlux篇 Reactor-Netty下HttpServer 的封裝Java程式設計SpringWebUXReactNettyHTTPServer封裝
- Spring Boot實現Web SocketSpring BootWeb
- Reactive Spring實戰 -- WebFlux使用教程ReactSpringWebUX
- spring-boot-route(十四)整合KafkaSpringbootKafka
- 【Reactor第八篇】WebFlux 服務編排ReactWebUX
- Spring Boot+RabbitMQ 通過fanout模式實現訊息接收(支援消費者多例項部署)Spring BootMQ模式
- 【翻譯】Reactor 第七篇 Spring WebFlux 怎麼進行異常處理ReactSpringWebUX
- mysql通過kafka實現資料實時同步(三)——es叢集配置MySqlKafka
- Spring Boot中實現Thymeleaf通知Spring Boot
- Spring Boot 開發整合 WebSocket,實現私有即時通訊系統Spring BootWeb
- Spring Boot通過@ConfigurationProperties訪問靜態資料 - reflectoringSpring Boot
- 在Spring boot中通過ApplicationContext獲取bean失敗Spring BootAPPContextBean
- 深入剖析 Spring WebFluxSpringWebUX
- Spring Boot 中的響應式程式設計和 WebFlux 入門Spring Boot程式設計WebUX
- 通過佇列實現棧OR通過棧實現佇列佇列
- 使用Spring Boot實現的GraphQL示例Spring Boot
- Spring Boot整合MyBatis實現通用MapperSpring BootMyBatisAPP
- 使用Spring Boot實現模組化Spring Boot