#chiroito ’s blog

Java を中心とした趣味の技術について

Spring Boot REST APIがそのままQuarkusで動くって本当?移行手順とパフォーマンス比較を公開

Java のクラウドネイティブ化が当たり前になり、軽量・高速なランタイムとして Quarkus を採用するケースが増えてきています。 一方で、既存アプリケーションの多くは Spring Boot で構築されており、

  • 本当に Quarkus へ移行できるのか
  • コードを書き直さないといけないのでは

といった印象を持たれがちです。

しかし実は、REST API アプリケーションであれば驚くほど簡単に動作します。 理由は、Quarkus が Spring Boot 互換 API を公式に提供しているためです。

今回は、次の公開サンプル(著者許諾済み)を題材に、Spring Boot の REST API を Quarkus へ移行する方法と、実際の性能差を紹介します。

https://github.com/projava17/examples/tree/main/part-6/chapter-21-spring-boot


結論:REST API アプリは“ほぼ変更なし”で Quarkus 上で動く

今回の移行検証では、REST API 部分は メソッドに public を追加するだけでそのまま Quarkus 上で動作しました。

Quarkus 側では Spring Web 互換レイヤー(quarkus-spring-web)が提供されているため、

  • @RestController
  • @RequestMapping
  • @GetMapping / @PostMapping

といったアノテーションはほぼ Spring Boot と同じように記述できます。

BFF のような薄い REST API アプリなら、コードを書き換える量は最小限で済みます


性能はどう変わったのか(実測値)

実際に計測すると、Quarkus へ移行するだけで次の改善が見られました。

項目 Spring Boot Quarkus 差分
起動時間 1.2 秒 0.58 秒 52% 短縮
起動後のメモリ使用量 12 MB 8 MB 33% 削減

つまり 書き換えほぼゼロで高速化が得られるということです。 これはクラウド環境ではコスト削減にも直結します。 メモリ使用量は、GCを何度か実行した後の値を取得しています。


移行の全体像

今回の移行ステップはとてもシンプルです。

  1. pom.xml を Spring Boot から Quarkus の BOM に書き換える
  2. Spring Boot 固有の起動クラス(TaskListApplication)を削除
  3. REST API のメソッドに public を付ける(Spring Boot は package-private でも動くが、Quarkus は public 必須)
  4. Thymeleaf を Qute に置き換える(今回は“おまけ”として後述)

まずは最も重要な pom.xml から見ていきます。


Spring Boot → Quarkus への pom.xml の変更ポイント

元の Spring Boot(抜粋)

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.6.3</version>
</parent>

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

Quarkus 用に書き換えた pom.xml(BOM + Spring Web 互換 API)

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-spring-web</artifactId>
</dependency>
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-rest-jackson</artifactId>
</dependency>

ここが最大のポイントです。 Spring Boot の Web API を提供する部分を Quarkus の Spring Web 互換レイヤーに差し替えるのみで、実際のコントローラ実装はそのまま利用できます。

pom.xmlのファイルは以下のようになります。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>jp.gihyo.projava</groupId>
    <artifactId>tasklist</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>TaskList</name>
    <description>Spring Bootを使ったタスク管理アプリケーション</description>
    <properties>
        <quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
        <quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
        <quarkus.platform.version>3.30.2</quarkus.platform.version>
        <surefire-plugin.version>3.1.2</surefire-plugin.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>${quarkus.platform.group-id}</groupId>
                <artifactId>${quarkus.platform.artifact-id}</artifactId>
                <version>${quarkus.platform.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-spring-web</artifactId>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-rest-jackson</artifactId>
        </dependency>
        <dependency>
            <groupId>io.quarkiverse.qute.web</groupId>
            <artifactId>quarkus-qute-web</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>${surefire-plugin.version}</version>
                <configuration>
                    <systemPropertyVariables>
                        <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
                        <maven.home>${maven.home}</maven.home>
                    </systemPropertyVariables>
                </configuration>
            </plugin>
            <plugin>
                <groupId>${quarkus.platform.group-id}</groupId>
                <artifactId>quarkus-maven-plugin</artifactId>
                <version>${quarkus.platform.version}</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>build</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

アプリケーション起動クラスは不要

Spring Boot の典型的な起動クラスは以下のような構造です。

@SpringBootApplication
public class TaskListApplication {
    public static void main(String[] args) {
        SpringApplication.run(TaskListApplication.class, args);
    }
}

Quarkus は ランタイムが起動処理を持つため、アプリ側で明示的に記述する必要がありません。 そのため、このクラスは削除します。


REST API の修正点:本当に “public を付けるだけ”

実際に変更したコードがこちらです。

Before(Spring Boot)

@RequestMapping(value = "/resthello")
String hello() {
    return """
            Hello.
            It works!
            現在時刻は%sです。
            """.formatted(LocalDateTime.now());
}

After(Quarkus)

@RequestMapping(value = "/resthello")
public String hello() {
    return """
            Hello.
            It works!
            現在時刻は%sです。
            """.formatted(LocalDateTime.now());
}

本当にこれだけです。 Spring Boot がメソッド可視性に寛容なのに対して、Quarkus は CDI の仕様上 public を要求するため、この差だけが必要となります。


まとめ:既存 Spring Boot REST API は “そのまま高速なランタイムで動かせる”

今回の検証で分かったのは次のポイントです。

  • REST API アプリなら ほぼ変更なしで Quarkus に移行可能
  • メソッドに public を付ける程度で動作
  • 互換 API により Spring Boot の資産を維持できる
  • 起動時間 50% 削減、メモリ 30% 削減と効果が大きい
  • BFF のような薄い API 層との相性が特に良い

“コードは Spring のまま、ランタイムだけ Quarkus で高速化” というアプローチは、既存プロジェクトの延命・最適化において非常に有効です。


おまけ:画面(HTML テンプレート)の移行

今回のアプリケーションには Thymeleaf の画面が含まれていますが、テンプレートエンジンの移行は別問題です。

  • Quarkus は @Controller を提供していない
  • Quarkus ではテンプレートエンジンとして Qute を使用する
  • Thymeleaf の名前空間や式はそのままでは使えない