Spring DI APIのためのQuarkusエクステンション
インジェクションにはCDIアノテーションを使用することが推奨されていますが、Quarkusでは、 spring-di
エクステンションという形で、Springのディペンデンシーインジェクションのための互換レイヤーを提供しています。
このガイドでは、Spring Frameworkに含まれる有名なDependency InjectionアノテーションをQuarkusアプリケーションでどのように活用するかを説明します。
前提条件
このガイドを完成させるには、以下が必要です:
-
約15分
-
IDE
-
JDK 17+がインストールされ、
JAVA_HOME
が適切に設定されていること -
Apache Maven 3.9.9
-
使用したい場合は、 Quarkus CLI
-
ネイティブ実行可能ファイルをビルドしたい場合、MandrelまたはGraalVM(あるいはネイティブなコンテナビルドを使用する場合はDocker)をインストールし、 適切に設定していること
ソリューション
次の章で紹介する手順に沿って、ステップを踏んでアプリを作成することをお勧めします。ただし、完成した例にそのまま進んでも構いません。
Gitレポジトリをクローンするか git clone https://github.com/quarkusio/quarkus-quickstarts.git
、 アーカイブ をダウンロードします。
ソリューションは spring-di-quickstart
ディレクトリ にあります。
Mavenプロジェクトの作成
まず、新しいプロジェクトが必要です。以下のコマンドで新規プロジェクトを作成します:
Windowsユーザーの場合:
-
cmdを使用する場合、(バックスラッシュ
\
を使用せず、すべてを同じ行に書かないでください)。 -
Powershellを使用する場合は、
-D
パラメータを二重引用符で囲んでください。例:"-DprojectArtifactId=spring-di-quickstart"
このコマンドは、プロジェクトを生成し、 spring-di
エクステンションをインポートします。
すでにQuarkusプロジェクトが設定されている場合は、プロジェクトのベースディレクトリで以下のコマンドを実行することで、 spring-di
エクステンションをプロジェクトに追加することができます。
quarkus extension add spring-di
./mvnw quarkus:add-extension -Dextensions='spring-di'
./gradlew addExtension --extensions='spring-di'
これにより、ビルドファイルに以下が追加されます:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-spring-di</artifactId>
</dependency>
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.properties
で greeting.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
./mvnw quarkus:dev
./gradlew --console=plain quarkusDev
ブラウザで http://localhost:8080/greeting を開きます。
結果は次のようになります: HELLO WORLD!
.
アプリケーションをネイティブバイナリーとして実行
もちろん、 こ のガイドと同様の手順でネイティブイメージを作成することもできます。
重要な技術的注意点
QuarkusのSpringサポートは、Springアプリケーションコンテキストを開始せず、Springインフラストラクチャクラスも実行しないことに注意してください。
Springのクラスとアノテーションは、メタデータの読み取りにのみ使用され、ユーザーコードのメソッドの戻り値の型やパラメータの型として使用されます。
これはエンドユーザーにとって、任意のSpringライブラリを追加しても効果がないことを意味します。
さらに、Springのインフラクラス(例えば org.springframework.beans.factory.config.BeanPostProcessor
、 org.springframework.context.ApplicationContext
)は実行されません。
依存性注入に関しては、Quarkusは Jakarta Contexts and Dependency Injection 4.1 仕様に基づいた依存性注入メカニズム(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 |
型が |
@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: Show more |
boolean |
|