Spring WebFluxとは

【連載】

マイクロサービス時代に活きるフレームワーク Spring WebFlux入門

【第1回】Spring WebFluxとは

[2020/12/09 08:00]伊藤司 ブックマーク ブックマーク

昨今、マイクロサービスアーキテクチャによるアプケーション開発がとても注目を集めています。マイクロサービスアーキテクチャでは、文字通り小さなサービスを多数組み合わせて1つのアプリケーションを構成することから、個々のサービスには高いリソース効率が求められます。また、従来のモノリシックなアプリケーションと比べて、サービス間通信が多く発生することから、高い処理能力(高スループット)も必要です。

Javaで高いリソース効率性と高い処理能力を持つアプリケーションを開発するためのフレームワークの一つとして、Spring Frameworkファミリーの「Spring WebFlux」があります。

本連載では、Spring WebFluxによるアプリケーションの作り方をはじめ、Spring WebFluxを理解する上で重要となる「リアクティブプログラミング」や、Spring WebFluxベースのHTTPクライアントである「WebClient」、Spring WebFluxと親和性の高いデータベースアクセスの仕組みである「R2DBC」を解説していきます。

なお、本連載では、Java/Spring Framework(Spring MVC)での開発経験がある開発者を想定しています。Spring Frameworkの開発経験がない場合には、Spring Frameworkを使った開発のベストプラクティス集「TERASOLUNA Server Framework Developement Guideline」のチュートリアルを実施することをお薦めします。

Spring WebFluxの概要

Spring FrameworkにはWebアプリケーションを作るためのフレームワークとして「Spring MVC」と「Spring WebFlux」の2つがあります。Spring MVCとSpring WebFluxの技術スタックには下図のような違いがあります。

Spring MVCとSpring WebFluxの技術スタック

Spring MVCとSpring WebFluxの技術スタック

Spring MVCはサーブレットをベースとしており、Tomcatなどのサーブレットコンテナの上で動作します。それに対して、Spring WebFluxはNettyなどのノンブロッキングI/Oベースのアプリケーションサーバの上で動作します。

ノンブロッキングI/O

「ノンブロッキングI/O」とは、ネットワークアクセスやDBアクセスなどのI/O処理の呼び出しに対して、読み書きができる場合は処理を行い、読み書きができない場合には即座に処理を戻すという仕組みです。読み書きができない場合に別の処理を行わせることができるため、CPUを効率的に利用することが可能になります。

Spring WebFluxでは、このノンブロッキングI/Oの仕組みを活かし、1つのスレッドで複数のリクエストを処理します。そのため、同時処理数分だけスレッドを必要とするSpring MVCなどと比べて、必要となるスレッド数が少なくなり、必要なメモリサイズも小さくなります。

リクエスト処理方式

また、ノンブロッキングな処理を実装しやすくするための仕組みとして、Spring WebFluxでは「Reactor」によるリアクティブプログラミングを採用しています。リアクティブプログラミングとは、データに着目したイベント駆動型のプログラミングの一種で、通知されるデータを受け取って処理を行うハンドラを実装することによって連続的なデータを処理する手法です。Reactorはリアクティブプログラミングを実現するためのライブラリの一つであり、ノンブロッキングで非同期なリアクティブプログラミングの仕組みを提供しています。

Spring WebFluxではReactorのAPIを使うことによって低レベルなノンブロッキングI/Oの仕組みを隠蔽し、より抽象度の高いかたちでノンブロッキングな処理を実装できるようにしています。

Spring WebFluxのユースケース/事例

Spring WebFluxの特徴は、リソース効率性と処理能力の高さです。そのため、冒頭でも述べたようにマイクロサービスアーキテクチャのシステムに適していると言えます。国内では、クックパッドのシステムにおいてAPIオーケストレーション層の実装として採用されている事例が開発者ブログで紹介されています。

また、マイクロサービスアーキテクチャではなくても、同時接続数が多いシステムであれば、Spring WebFluxを採用することでインフラコストを抑えることが可能です。例えば、LINEの内部では一部Spring WebFluxを使用しているとの事例が公開されています。そのほか、同時接続数が多いものとしてはIoTの領域において多数のセンサデータを処理するシステムなどが挙げられます。

Spring WebFluxによるHello Worldアプリケーションの作成

それでは実際にSpring WebFluxを使ったHello Worldアプリケーションを作成してみましょう。ここでは、「Spring Initializr」を使ってプロジェクトのひな型を作成します。

まず、Spring Initializrにアクセスします。 画面左側の各種パラメータを下記のように指定します。

パラメータ 設定値
Project Maven Project
Language Java
Spring Boot 2.3.4
Group com.example
Artifact demo
Name demo
Description Demo project for Spring Boot
Package Name com.example.demo
Packaging Jar
Java 15
各種パラメータの設定

画面右上の「ADD DEPENDENCIES」を選択し、表示されるダイアログの中から「Spring Reactive Web」を選択します。 そして、画面下部の「GENERATE」を選択し、プロジェクトのひな型をZIPファイルとしてダウンロードします。

「Spring Reactive Web」を選択

次に生成したプロジェクトひな型の中身を確認してみましょう。ZIPファイルを解凍すると以下のような構成になっています。

ディレクトリ構成

ここで「pom.xml」の内容を確認してみます。すると、以下のように依存関係としてspring-boot-starter-webfluxが含まれています。これがSpring BootでSpring WebFluxのアプリケーションを作る際のスターターになります。

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>
</dependencies>

そのほか、テストスコープの依存関係としてreactor-testも含まれています。

続いて、Hello Worldを返すエンドポイントを実装していきます。Spring WebFluxには、アノテーションとクラスを使った実装方法と、HandlerFunctionやRouterFunctionなどの関数を利用した関数型プログラミングによる実装方法がありますが、本連載では、アノテーションとクラスを使った実装方法で解説します。また、説明上、一部リアクティブプログラミングの用語(Reactor、Monoなど)が出てきますが、これらについては次回詳しく解説します。

package com.example.demo;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;

@RestController                             // (1)
public class HelloWorldController {

    @GetMapping("/greeting")                // (2)
    public Mono<String> greeting() {        // (3)
        return Mono.just("Hello World!");   // (4)
    }
}
項番 説明
1 Spring Web MVCと同様、@RestControllerアノテーションを付与することでREST APIのControllerクラスとして指定することができます
2 Spring Web MVCと同様、@GetMappingアノテーションを付与することでGETリクエストに対応するエンドポイントを指定することができます
3 メソッドの返り値の型として、Reactorの型であるMonoクラスを指定しています
4 "Hello World!"の文字列を出力するMonoを生成して返却します

それではアプリケーションを起動してみましょう。 ターミナルを開き、プロジェクトのルートディレクトリ上でmvnwコマンドを実行します。

$ ./mvnw spring-boot:run
[INFO] Scanning for projects...
[INFO]
[INFO] --------------------------< com.example:demo >--------------------------
[INFO] Building demo 0.0.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] >>> spring-boot-maven-plugin:2.3.4.RELEASE:run (default-cli) > test-compile @ demo >>>
[INFO]
[INFO] --- maven-resources-plugin:3.1.0:resources (default-resources) @ demo ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 1 resource
[INFO] Copying 0 resource
[INFO]
[INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ demo ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to /Users/media/Downloads/demo/target/classes
[INFO]
[INFO] --- maven-resources-plugin:3.1.0:testResources (default-testResources) @ demo ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /Users/media/Downloads/demo/src/test/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ demo ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to /Users/media/Downloads/demo/target/test-classes
[INFO]
[INFO] <<< spring-boot-maven-plugin:2.3.4.RELEASE:run (default-cli) < test-compile @ demo <<<
[INFO]
[INFO]
[INFO] --- spring-boot-maven-plugin:2.3.4.RELEASE:run (default-cli) @ demo ---
[INFO] Attaching agents: []

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.3.4.RELEASE)

2020-10-30 00:58:50.233  INFO 6663 --- [           main] com.example.demo.DemoApplication         : Starting DemoApplication on GeorgeMedianoMacBook-Pro.local with PID 6663 (/Users/media/Downloads/demo/target/classes started by media in /Users/media/Downloads/demo)
2020-10-30 00:58:50.236  INFO 6663 --- [           main] com.example.demo.DemoApplication         : No active profile set, falling back to default profiles: default
2020-10-30 00:58:51.609  INFO 6663 --- [           main] o.s.b.web.embedded.netty.NettyWebServer  : Netty started on port(s): 8080
2020-10-30 00:58:51.621  INFO 6663 --- [           main] com.example.demo.DemoApplication         : Started DemoApplication in 2.058 seconds (JVM running for 2.432)

標準出力の内容を見てみると、Nettyサーバが起動していることが分かります。 続いて、curlで先ほど実装したエンドポイントにアクセスし、「Hello World!」の文字列が返ってくることを確認してみましょう。

$ curl http://localhost:8080/greeting
Hello World!

* * *

今回はSpring WebFluxの概要と簡単なアプリケーションの作り方を解説しました。次回は、Spring WebFluxを使う上で欠かせない要素であるリアクティブプログラミングについて詳しく解説します。

著者紹介

伊藤 司(Ito Tsukasa) - NTTデータ

テスト技術のR&D、システム開発のプロセス標準整備などを経て、現在は一般企業向けの業務システム開発に従事。アプリケーションのアーキテクチャ設計のほか、クラウド基盤の設計・構築なども行っている。

また、システム開発の業務のかたわら、アプリケーションフレームワークやコンテナ、Kubernetesなどの技術検証も行っている。

※ 本記事は掲載時点の情報であり、最新のものとは異なる場合がございます。予めご了承ください。

もっと知りたい!こちらもオススメ

【連載】いまさら聞けないマイクロサービスの基本 [1] マイクロサービスを理解するための3つのポイント

【連載】いまさら聞けないマイクロサービスの基本 [1] マイクロサービスを理解するための3つのポイント

マイクロサービス(Microservies)という言葉を聞いたことがあるでしょうか。昨今急速に認知度が高まっていて、技術セミナーなどで耳にすることも多くなってきました。それでも、クラウドやアジャイルといった用語と比べるとまだまだ理解度は低いようです。

関連リンク

この記事に興味を持ったら"いいね!"を Click
Facebook で IT Search+ の人気記事をお届けします
注目の特集/連載
[解説動画] Googleアナリティクス分析&活用講座 - Webサイト改善の正しい考え方
[解説動画] 個人の業務効率化術 - 短時間集中はこうして作る
ミッションステートメント
教えてカナコさん! これならわかるAI入門
AWSではじめる機械学習 ~サービスを知り、実装を学ぶ~
対話システムをつくろう! Python超入門
Kubernetes入門
SAFeでつくる「DXに強い組織」~企業の課題を解決する13のアプローチ~
PowerShell Core入門
AWSで作るマイクロサービス
マイナビニュース スペシャルセミナー 講演レポート/当日講演資料 まとめ
セキュリティアワード特設ページ

一覧はこちら

今注目のIT用語の意味を事典でチェック!

一覧はこちら

会員登録(無料)

ページの先頭に戻る