レスポンシブ プログラミングの実践 (08) - WebFlux、アノテーション プログラミング モードを使用して非同期ノンブロッキング サービスを構築する

1 はじめに

SpringファミリーにおけるWebFluxコンポーネント誕生の背景と意義を明らかにする。新しいタイプの Web サービス開発コンポーネントとして:

  • 元の Spring MVC 開発モデルとの互換性を十分に考慮しているため、開発者は注釈ベースのプログラミングを使用して応答性の高い Web サービスを作成できます。
  • WebFlux では、関数型プログラミングに基づく新しい開発モデルも導入しています。

まず、注釈ベースのプログラミング モデルに焦点を当てます。

2 Spring WebFlux の紹介

初めて WebFlux アプリケーションを作成する場合は、Spring が提供する Spring Initializer 初期化テンプレートを使用するのが最も簡単です。Spring Initializer Web サイト ( http://start.spring.io/ ) に直接アクセスし、Maven プロジェクトの作成を選択して対応する構成項目を指定し、追加された依存関係で Spring Reactive Web を選択すると、実行可能な WebFlux テンプレートを取得できます。計画。

図面 0.png

Spring Initializer で初期化されたレスポンシブ Web アプリケーションの図。

テンプレートプロジェクト内のpomファイル

<dependencies>      
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
 
        <dependency>
            <groupId>io.projectreactor</groupId>
            <artifactId>reactor-test</artifactId>
            <scope>test</scope>
        </dependency>       
</dependencies>
  • コアは spring-boot-starter-webflux で、レスポンシブな Web アプリケーション開発の基礎を形成します。
  • spring-boot-starter-test は、JUnit、Spring Boot Test、Mockit、その他の一般的なテスト ツール クラスを含むテスト コンポーネント ライブラリです。
  • actor-test は、Reactor フレームワークをテストするために使用されるテスト コンポーネント ライブラリです。

もちろん、任意の Maven プロジェクトを作成して、これらの依存関係を追加することもできます。このようにして、Spring WebFlux でリアクティブ Web サービスを構築するための初期化環境が準備されました。

3 アノテーション プログラミング モデルを使用して応答性の高い RESTful サービスを作成する

  • Java アノテーションに基づいたこのプログラミング モデルは、従来の Spring MVC と一貫しています。
  • 関数型プログラミング モデルを使用する

まず最初の実装を紹介します。

3.1 RESTful サービスと従来の作成方法

レスポンシブ Web サービスを作成する前に、従来の RESTful サービスの作成方法を確認してみましょう。

REST (Representational State Transfer) は本質的に仕様ではなくアーキテクチャ スタイルです。このアーキテクチャ スタイルでは、サーバー側にあるアクセス ポータルをリソースとみなし、各リソースは URI を使用して一意のアクセス アドレスを表します。リクエスト プロセスでは、GET、PUT、POST、DELETE などの標準 HTTP メソッドが使用されます。

Spring Boot を使用して従来の RESTful サービスを構築し、Bootstrap スタートアップ クラスを作成します。Bootstrap クラスの構造はシンプルで比較的堅牢です。

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
 
@SpringBootApplication
public class HelloApplication {
    
    
 
    public static void main(String[] args) {
    
    
        SpringApplication.run(HelloApplication.class, args);
    }
}

@SpringBootApplication アノテーションが付けられたクラスはアプリケーション全体のエントリ クラスであり、Spring コンテナを起動することに相当します。Spring コンテナが起動したら、一連のコントローラー クラスを提供することで HTTP エンドポイントを構築できます。その中で最も単純なものを以下に示します。

@RestController
public class HelloController {
    
    
 
    @GetMapping("/")
    public String hello() {
    
    
        return "Hello World!";
    }
}

@RestController アノテーションは、Spring MVC の @Controller アノテーションを継承します。従来の @Controller アノテーションと比較して、@RestController アノテーションには JSON ベースのシリアル化/逆シリアル化メソッドが組み込まれており、これは軽量の RESTful エンドポイントを構築するために特別に使用されます。この機能を使用すると、@Controller アノテーションの代わりに @RestController アノテーションを使用して、RESTful サービスを構築する際の開発を簡素化できます。

@GetMapping アノテーションも Spring MVC の @RequestMapping アノテーションに似ています。Spring Boot 2 では、開発者が HTTP リクエスト メソッドを明示的に指定できるようにするために、@PutMapping、@PostMapping、@DeleteMapping などの新しいアノテーションのバッチが導入されています。もちろん、元の @RequestMapping を引き続き使用して、同じ効果を達成することもできます。

一般的なコントローラ

注文番号 OrderNumber に従って注文情報を取得する HTTP エンドポイントを実装しました。このエンドポイントのアクセス URI は「orders/{orderNumber}」で、ルート パス「orders」+サブパス「/{orderNumber}」で構成され、対応する HTTP リクエスト メソッドと必要なパラメーターも指定します。

@RestController
@RequestMapping(value="orders")
public class OrderController {
    
    
  
    @Autowired
    private OrderService orderService;       
    
    @GetMapping(value = "/{orderNumber}")
    public Order getOrderByOrderNumber(@PathVariable String orderNumber) {
    
       
        Order order = orderService.getOrderByOrderNumber(orderNumber);
        
        return order;
    }
}

アノテーション プログラミング モデルに基づいてレスポンシブ RESTful サービスを作成することは、従来の Spring MVC を使用することと非常に似ています。レスポンシブ プログラミングの基本概念とスキルをマスターすれば、WebFlux アプリケーションでこのプログラミング モデルを使用するための学習コストはほとんどかかりません。

3.2 アノテーションによる応答性の高い RESTful サービスの構築

前に紹介した 2 つの RESTful サービスの例について、リアクティブ プログラミング モデルに関してリアクティブ バージョンを与える方法を示します。

最初の応答性の高い RESTful サービスは、元の HelloController サンプルの応答性の高い変換から来ています。

変換後:

@RestController
public class HelloController {
    
    
 
    @GetMapping("/")
    public Mono<String> hello() {
    
    
        return Mono.just("Hello World!");
    }
}

hello() メソッドの戻り値は、通常の String オブジェクトから Mono オブジェクトに変換されます。

Spring WebFlux と Spring MVC の違いは、前者は POJO の代わりに Reactor で提供される Flux オブジェクトと Mono オブジェクトを使用することです。

最初のリアクティブ RESTful サービスは非常に単純です。以下では、さらに一歩進んで、サービス層実装を使用してリアクティブ RESTful サービスを構築します。サービス層は通常、特定のデータ アクセス層を使用してデータ操作を実装しますが、レスポンシブ データ アクセスは独立したトピックであるため、フォローアップ「14 | レスポンシブ フルスタック: レスポンシブ プログラミングでデータ アクセスを提供できるのはどのようなものか」で説明します。プロセスがもたらす変化は?」を展開します。

この講演では、応答性の高いデータ アクセスによってもたらされる複雑さを保護しようとします。データ層は、スタブを使用してこのサービス層コンポーネントを実装します。以下に示すように、一般的な注文サービス用のスタブ サービス StubOrderService を構築します。

@Service
public class StubOrderService {
    
    
 
    private final Map<String, Order> orders = new ConcurrentHashMap<>();
 
    public Flux<Order> getOrders() {
    
    
        return Flux.fromIterable(this.orders.values());
    }
 
    public Flux<Order> getOrdersByIds(final Flux<String> ids) {
    
    
        return ids.flatMap(id -> Mono.justOrEmpty(this.orders.get(id)));
    }
 
    public Mono<Order> getOrdersById(final String id) {
    
    
        return Mono.justOrEmpty(this.orders.get(id));
    }
 
    public Mono<Void> createOrUpdateOrder(final Mono<Order> productMono) {
    
    
        return productMono.doOnNext(product -> {
    
    
            orders.put(product.getId(), product);
        }).thenEmpty(Mono.empty());
    }
 
    public Mono<Order> deleteOrder(final String id) {
    
    
        return Mono.justOrEmpty(this.orders.remove(id));
    }
}

StubOrderService は、注文データに対して基本的な CRUD 操作を実行するために使用されます。メモリ内にある ConcurrentHashMap オブジェクトを使用してすべての Order オブジェクト情報を保存し、スタブ コードの実装を提供します。

ここでの getOrdersByIds() メソッドは代表的なもので、Flux タイプのパラメータ ID を受け取ります。Flux 型のパラメータは、処理対象のオブジェクトが複数あることを表しますが、ここでは「07 | Reactor オペレータ (前編): レスポンシブなフローを素早く変換するには?」で紹介した flatMap オペレータを使用して、受信する ID をそれぞれ処理します。これは、 flatMap オペレーターの非常に一般的な使用法でもあります。

さらに、createOrUpdateOrder() メソッドは、Mono.doOnNext() メソッドを使用して、Mono オブジェクトを通常の POJO オブジェクトに変換し、保存します。doOnNext() メソッドは、リアクティブ フローが onNext 通知を送信するたびに、カスタマイズされた処理をメッセージに追加するのと同じです。

スタブ サービス StubOrderService を使用すると、StubOrderController を作成して、StubOrderService を使用して特定のエンドポイントを完了する特定の応答性の高い RESTful サービスを構築できます。

StubOrderController の公開エンドポイントは非常にシンプルで、特定の関数を StubOrderService の対応するメソッドに委任するだけです。

@RestController
@RequestMapping("/orders")
public class StubOrderController {
    
    
 
    @Autowired
    private StubOrderService orderService;
 
    @GetMapping("")
    public Flux<Order> getOrders() {
    
    
        return this.orderService.getOrders();
    }
 
    @GetMapping("/{id}")
    public Mono<Order> getOrderById(@PathVariable("id") final String id) {
    
    
        return this.orderService.getOrderById(id);
    }
 
    @PostMapping("")
    public Mono<Void> createOrder(@RequestBody final Mono<Order> order) {
    
    
        return this.orderService.createOrUpdateOrder(order);
    }
 
    @DeleteMapping("/{id}")
    public Mono<Order> delete(@PathVariable("id") final String id) {
    
    
        return this.orderService.deleteOrder(id);
    }
}

WebFlux は Spring MVC と同じアノテーションをサポートします。主な違いは、基礎となる通信メソッドがブロックされるかどうかです。

  • シンプルなシナリオ、両者に大きな違いはありません
  • 複雑なアプリケーションの場合、応答性の高いプログラミングとバック プレッシャーの利点が反映され、全体的なパフォーマンスが向上します。

4 ケースの統合: ReactiveSpringCSS の Web サービス

顧客サービス システムとしての中心的なビジネス プロセスは、顧客サービスの作業指示書を生成することであり、作業指示書の生成には通常、ユーザー アカウント情報と関連する注文情報の使用が必要です。

このケースには、次の 3 つの個別の Web サービスが含まれています。

  • 注文を管理するための order-service

  • account-ユーザーアカウントを管理するためのサービス

  • コアカスタマーサービス カスタマーサービス

サービスがどのように相互作用するか:

ReactiveSpringCSS ケース システムの 3 つのサービスの相互作用図

このインタラクティブな図を通じて、作業指示書生成の中核プロセスの疑似コードを整理できます。

generateCustomerTicket {
    
    
 
  创建 CustomerTicket 对象
 
	从远程 account-service 中获取 Account 对象
 
	从远程 order-service 中获取 Order 对象
 
	设置 CustomerTicket 对象属性
 
	保存 CustomerTicket 对象并返回
}
  • [リモートアカウントサービスからアカウントオブジェクトを取得]
  • [リモートの order-service から Order オブジェクトを取得する]

どちらもリモート Web サービスへのアクセスを必要とします。

まず、account-service サービスと order-service サービスに対応する HTTP エンドポイントをそれぞれ作成します。

まず、アノテーション プログラミング モデルに基づいて、アカウント サービスでの AccountController の実装プロセスが示され、完全な AccountController が提供されます。

@RestController
@RequestMapping(value = "accounts")
public class AccountController {
    
    
 
    @Autowired
    private AccountService accountService;
 
    @GetMapping(value = "/{accountId}")
    public Mono<Account> getAccountById(@PathVariable("accountId") String accountId) {
    
    
 
        Mono<Account> account = accountService.getAccountById(accountId);
        return account;
    }
 
    @GetMapping(value = "accountname/{accountName}")
    public Mono<Account> getAccountByAccountName(@PathVariable("accountName") String accountName) {
    
    
 
        Mono<Account> account = accountService.getAccountByAccountName(accountName);
        return account;
    }
 
    @PostMapping(value = "/")
    public Mono<Void> addAccount(@RequestBody Mono<Account> account) {
    
    
        
        return accountService.addAccount(account);
    }
 
    @PutMapping(value = "/")
    public Mono<Void> updateAccount(@RequestBody Mono<Account> account) {
    
    
        
        return accountService.updateAccount(account);
    }
}

ここでのいくつかの HTTP エンドポイントは比較的単純で、基本的に AccountService によって完了される CRUD 操作に基づいています。addAccount と updateAccount の 2 つのメソッドでは、入力パラメーターは Account オブジェクトではなく Mono オブジェクトであることに注意してください。これは、AccountController がクライアントからのリクエストを応答性の高いフローで処理することを意味します。

要約する

今日から、応答性の高い RESTful Web サービスを構築するための Spring WebFlux を紹介します。WebFlux は、まったく新しい開発フレームワークとして、幅広いアプリケーション シナリオを備え、2 つの異なる開発モデルをサポートします。本講義では、アノテーションプログラミングモデルによるRESTfulサービスの開発方法を解説します。

よくある質問

Spring WebFlux と Spring MVC を使用して RESTful サービスを開発する場合の関係と違いは何ですか?

Spring WebFlux と Spring MVC を使用した RESTful サービスの開発は Spring フレームワークに基づいており、これらには次のような関連性と相違点があります。

接続:

  1. どちらも RESTful サービスの開発に使用でき、HTTP プロトコルの GET、POST、PUT、DELETE およびその他のリクエスト メソッドをサポートします。
  2. @RequestMapping、@GetMapping、@PostMapping など、Spring によって提供されるアノテーションを使用して開発を簡素化できます。
  3. Spring が提供するインターセプターを使用して、リクエストの前後のロジックを処理できます。

違い:

  1. プログラミング モデルは異なります。Spring WebFlux はリアクティブ プログラミング モデルに基づいており、Reactor ライブラリを使用して非同期およびノンブロッキング I/O 操作を処理します。一方、Spring MVC は従来のサーブレット API に基づいており、ブロッキング I/O 操作を使用します。
  2. スレッド モデルは異なります。Spring WebFlux は少数のスレッドを使用して多数の同時リクエストを処理し、Reactor ライブラリが提供するイベント ループ メカニズムを通じてノンブロッキング I/O 操作を実装します。Spring MVC はスレッド プールを使用してリクエストを処理し、各リクエストはスレッドを占有します。
  3. リアクティブ サポートは異なります。Spring WebFlux はリアクティブ プログラミングをサポートしており、Mono 型と Flux 型を使用して非同期操作とストリーミング データを処理できます。Spring MVC はリアクティブ プログラミングをサポートしていません。
  4. 例外処理は異なります: Spring WebFlux の例外処理メカニズムは、関数型プログラミング モデルを使用して例外を処理する Spring MVC とは異なります。WebFlux では、例外ハンドラーは ServerRequest オブジェクトと Throwable オブジェクトを受け取り、Mono オブジェクトを返す関数です。Spring MVC では、例外ハンドラーは HandlerExceptionResolver インターフェースを実装する必要があるクラスです。
  5. 異なるパフォーマンスと同時実行性: Spring WebFlux は少数のスレッドを使用して多数の同時リクエストを処理するため、サービス拒否攻撃からシステムをより適切に保護できます。一方、Spring MVC はリクエストを処理するためにスレッド プールを使用する必要があるため、サービス拒否攻撃に対して脆弱です。

つまり、Spring WebFlux と Spring MVC のどちらを使用するかは、特定のアプリケーションのシナリオと要件によって決まります。大量の同時リクエストを処理する必要があり、応答性の高いプログラミング モデルを使用して高いパフォーマンスと高い同時実行性を実現したい場合は、Spring WebFlux を選択できます。アプリケーション シナリオが比較的単純な場合は、Spring MVC を選択できます。

次の記事では、引き続き Spring WebFlux のアプリケーションについて説明し、新しい関数型プログラミング モデルのプログラミング コンポーネントを分析し、ReactiveSpringCSS との統合を完了します。

おすすめ

転載: blog.csdn.net/qq_33589510/article/details/131640216