The English version of quarkus.io is the official project site. Translated sites are community supported on a best-effort basis.

Spring DI APIのためのQuarkusエクステンション

インジェクションにはCDIアノテーションを使用することが推奨されていますが、Quarkusでは、 spring-di エクステンションという形で、Springのディペンデンシーインジェクションのための互換レイヤーを提供しています。

このガイドでは、Spring Frameworkに含まれる有名なDependency InjectionアノテーションをQuarkusアプリケーションでどのように活用するかを説明します。

前提条件

このガイドを完成させるには、以下が必要です:

  • 約15分

  • IDE

  • JDK 17+がインストールされ、 JAVA_HOME が適切に設定されていること

  • Apache Maven 3.9.6

  • 使用したい場合は、 Quarkus CLI

  • ネイティブ実行可能ファイルをビルドしたい場合、MandrelまたはGraalVM(あるいはネイティブなコンテナビルドを使用する場合はDocker)をインストールし、 適切に設定していること

ソリューション

次の章で紹介する手順に沿って、ステップを踏んでアプリを作成することをお勧めします。ただし、完成した例にそのまま進んでも構いません。

Gitレポジトリをクローンするか git clone https://github.com/quarkusio/quarkus-quickstarts.gitアーカイブ をダウンロードします。

ソリューションは spring-di-quickstart ディレクトリ にあります。

Mavenプロジェクトの作成

まず、新しいプロジェクトが必要です。以下のコマンドで新規プロジェクトを作成します:

コマンドラインインタフェース
quarkus create app org.acme:spring-di-quickstart \
    --extension='resteasy-reactive,spring-di' \
    --no-code
cd spring-di-quickstart

Gradleプロジェクトを作成するには、 --gradle または --gradle-kotlin-dsl オプションを追加します。

Quarkus CLIのインストールと使用方法の詳細については、 Quarkus CLI ガイドを参照してください。

Maven
mvn io.quarkus.platform:quarkus-maven-plugin:3.8.3:create \
    -DprojectGroupId=org.acme \
    -DprojectArtifactId=spring-di-quickstart \
    -Dextensions='resteasy-reactive,spring-di' \
    -DnoCode
cd spring-di-quickstart

Gradleプロジェクトを作成するには、 -DbuildTool=gradle または -DbuildTool=gradle-kotlin-dsl オプションを追加します。

Windowsユーザーの場合:

  • cmdを使用する場合、(バックスラッシュ \ を使用せず、すべてを同じ行に書かないでください)。

  • Powershellを使用する場合は、 -D パラメータを二重引用符で囲んでください。例: "-DprojectArtifactId=spring-di-quickstart"

このコマンドは、プロジェクトを生成し、 spring-di エクステンションをインポートします。

すでにQuarkusプロジェクトが設定されている場合は、プロジェクトのベースディレクトリで以下のコマンドを実行することで、 spring-di エクステンションをプロジェクトに追加することができます。

コマンドラインインタフェース
quarkus extension add spring-di
Maven
./mvnw quarkus:add-extension -Dextensions='spring-di'
Gradle
./gradlew addExtension --extensions='spring-di'

これにより、ビルドファイルに以下が追加されます:

pom.xml
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-spring-di</artifactId>
</dependency>
build.gradle
implementation("io.quarkus:quarkus-spring-di")

Springアノテーションを使用したBeanの追加

それでは、さまざまなSpringアノテーションを使って、いくつかのBeanを作成してみましょう。

まず、 StringFunction インターフェースを作成します。これは、いくつかのBeanがこれから実装し、後に別のBeanに注入されます。 src/main/java/org/acme/spring/di/StringFunction.java ファイルを作成し、以下の内容を設定します:

package org.acme.spring.di;

import java.util.function.Function;

public interface StringFunction extends Function<String, String> {

}

インターフェイスが整ったところで、SpringのJava Configスタイルを使ってBeanを定義する AppConfiguration クラスを追加します。これを使って、パラメータとして渡されたテキストを大文字にする StringFunction Beanを作成します。以下の内容で src/main/java/org/acme/spring/di/AppConfiguration.java ファイルを作成します:

package org.acme.spring.di;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfiguration {

    @Bean(name = "capitalizeFunction")
    public StringFunction capitalizer() {
        return String::toUpperCase;
    }
}

Springの開発者であれば、追加のBeanをスキャンする特定のパッケージを定義するために、 @ComponentScan アノテーションを追加したいと思うかもしれません。しかし、Quarkusは可視性の境界がない annotated モードでのみ Beanディスカバリー を行うため、 @ComponentScan は全く必要ないことに注意してください。さらに、QuarkusでのBeanディスカバリーはビルド時に行われることに注意してください。同じように、QuarkusはSpringの @Import アノテーションをサポートしていません。

次に、Springのステレオタイプアノテーションスタイルを使用して、 StringFunction を実装する別のBeanを定義します。このBeanは、事実上、入力をそのまま返すだけのno-op beanとなります。 src/main/java/org/acme/spring/di/NoOpSingleStringFunction.java ファイルを作成し、以下の内容を設定します:

package org.acme.spring.di;

import org.springframework.stereotype.Component;

@Component("noopFunction")
public class NoOpSingleStringFunction implements StringFunction {

    @Override
    public String apply(String s) {
        return s;
    }
}

Quarkusは、Springの @Value アノテーションを使用して設定値を注入するサポートも提供しています。動作を確認するには、まず、以下の内容で src/main/resources/application.properties を編集します:

# Your configuration properties
greeting.message = hello

次に、 src/main/java/org/acme/spring/di/MessageProducer.java に以下の内容で新しいSpring Beanを作成します:

package org.acme.spring.di;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

@Service
public class MessageProducer {

    @Value("${greeting.message}")
    String message;

    public String getPrefix() {
        return message;
    }
}

最後に作成するBeanは、これまでのBeanをすべて結びつけるものです。 src/main/java/org/acme/spring/di/GreeterBean.java ファイルを作成し、以下の内容をコピーします:

package org.acme.spring.di;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class GreeterBean {

    private final MessageProducer messageProducer;

    @Autowired
    @Qualifier("noopFunction")
    StringFunction noopStringFunction;

    @Autowired
    @Qualifier("capitalizeFunction")
    StringFunction capitalizerStringFunction;

    @Value("${greeting.suffix:!}")
    String suffix;

    public GreeterBean(MessageProducer messageProducer) {
        this.messageProducer = messageProducer;
    }

    public String greet(String name) {
        final String initialValue = messageProducer.getPrefix() + " " + name + suffix;
        return noopStringFunction.andThen(capitalizerStringFunction).apply(initialValue);
    }
}

上のコードでは、フィールドインジェクションとコンストラクタインジェクションの両方が使用されていることがわかります(コンストラクタインジェクションでは、コンストラクタが 1 つなので、 @Autowired のアノテーションは必要ないことに注意してください)。さらに、 suffix@Value アノテーションには、デフォルト値も定義されています。この場合、 application.propertiesgreeting.suffix を定義していないので、これが使用されます。

Jakarta RESTリソースの作成

src/main/java/org/acme/spring/di/GreeterResource.java のファイルを以下の内容で作成します:

package org.acme.spring.di;

import org.springframework.beans.factory.annotation.Autowired;

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;

@Path("/greeting")
public class GreeterResource {

    @Autowired
    GreeterBean greeterBean;

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String hello() {
        return greeterBean.greet("world");
    }
}

テストの更新

また、エンドポイントに加えられた変更を反映させるために、機能テストを更新する必要があります。 src/test/java/org/acme/spring/di/GreetingResourceTest.java ファイルを編集し、 testHelloEndpoint メソッドの内容を次のように変更します。

import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Test;

import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.is;

@QuarkusTest
public class GreetingResourceTest {

    @Test
    public void testHelloEndpoint() {
        given()
            .when().get("/greeting")
            .then()
                .statusCode(200)
                .body(is("HELLO WORLD!"));
    }

}

アプリケーションをパッケージ化して実行する

以下のコマンドでアプリケーションを実行します:

コマンドラインインタフェース
quarkus dev
Maven
./mvnw quarkus:dev
Gradle
./gradlew --console=plain quarkusDev

ブラウザで http://localhost:8080/greeting を開きます。

結果は次のようになります: HELLO WORLD!.

アプリケーションをネイティブバイナリーとして実行

もちろん、 のガイドと同様の手順でネイティブイメージを作成することもできます。

重要な技術的注意点

QuarkusのSpringサポートは、Springアプリケーションコンテキストを開始せず、Springインフラストラクチャクラスも実行されないことに注意してください。Springクラスとアノテーションは、メタデータの読み取りと、ユーザーコードのメソッドの戻り値の型やパラメータの型として使用されるだけです。つまり、エンドユーザーにとっては、任意のSpringライブラリを追加しても、何の効果もないということです。また、Springのインフラストラクチャークラス(例えば、 org.springframework.beans.factory.config.BeanPostProcessororg.springframework.context.ApplicationContext )は、実行されません。依存性注入に関しては、Quarkusは Contexts and Dependency Injection for Java 2.0 仕様に基づく依存性注入メカニズム(ArCと呼ばれます)を使用しています。CDIについて詳しく知りたい場合は、 QuarkusのCDI入門CDIリファレンスガイド を読むことをお勧めします。 Spring Bootのさまざまなテスト機能は、Quarkusではサポートされていません。テスト目的であれば、 Quarkusテストガイド をご確認ください。

いくつかの既知の制約があります:

  • 曖昧な場合、SpringはBean名と注入ポイントのフィールド名やパラメータ名の照合を行います。これはサポートされていないので、 @Named アノテーションを使用して曖昧さを明示的に解決する必要があります。

  • 特定のタイプのすべての Bean を注入することは、 List<Bean> に限定されます。 Set<Bean>Map<String, Bean> を注入することは、サポートされていません。

  • @Autowired(required=false) を使用したオプショナルな注入はサポートされていません。 javax.enterprise.inject.Instance を使用し、その後 Instance.isResolvable() をテストしてください。

  • @Conditional は無視されます。依存性注入はビルド時に解決されるからです。代替案としては、 条件付きビルドプロファイル を使用する方法があります。

変換テーブル

以下の表は、Spring DIのアノテーションをCDIおよび/またはMicroProfileのアノテーションに変換する方法を示しています。

Spring CDI / MicroProfile Comments

@Autowired

@Inject

型が java.util.List の場合、 io.quarkus.arc.All の修飾子が付加されます。

@Qualifier

@Named

@Value

@ConfigProperty

ConfigurationProperty は、@Value とは違って式言語をサポートしていませんが、典型的な使用例をはるかに簡単に扱うことができます

@Component

@Singleton

デフォルトでは、SpringのステレオタイプアノテーションはシングルトンBeanです

@Service

@Singleton

デフォルトでは、SpringのステレオタイプアノテーションはシングルトンBeanです

@Repository

@Singleton

デフォルトでは、SpringのステレオタイプアノテーションはシングルトンBeanです

@Configuration

@ApplicationScoped

CDIでは、プロデューサBeanはアプリケーションスコープに限定されず、@Singletonや@Dependentにすることもできます

@Bean

@Produces

@Scope

CDI アノテーションへの 1 対 1 のマッピングはありません。Scope の値に応じて、@Singleton、@ApplicationScoped、@SessionScoped、@RequestScoped、@Dependent のいずれかが使用されます

@ComponentScan

CDIアノテーションへの1対1のマッピングはありません。Quarkusはビルド時にすべてのクラスパスのスキャンを行うため、Quarkusでは使用されません。

@Import

CDIアノテーションとの1対1のマッピングはありません。

Spring DI 設定リファレンス

ビルド時に固定される構成プロパティ - 他のすべての構成プロパティは実行時にオーバーライド可能

Configuration property

デフォルト

Whether Spring DI is enabled **during the build**.

Turning this setting off will result in Quarkus completely ignoring beans annotated with Spring annotations

Environment variable: QUARKUS_SPRING_DI_ENABLED

Show more

boolean

true

関連コンテンツ