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

Accessing application properties with Spring Boot properties API

Quarkusネイティブの @ConfigProperties や MicroProfile @ConfigProperty のアプローチではなく、Spring Boot @ConfigurationProperties アノテーションクラスを使用してアプリケーションのプロパティーにアクセスしたい場合は、このエクステンションを使用することができます。

Spring Boot @ConfigurationProperties has a few limitations. For instance, Map injection is not supported. Consider using Mapping configuration to objects.

前提条件

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

  • 約15分

  • IDE

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

  • Apache Maven 3.8.1+

  • 使用したい場合、 Quarkus CLI

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

ソリューション

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

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

The solution is located in the spring-boot-properties-quickstart directory.

Mavenプロジェクトの作成

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

CLI
quarkus create app org.acme:spring-boot-properties-quickstart \
    --extension=resteasy-reactive,spring-boot-properties \
    --no-code
cd spring-boot-properties-quickstart

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

Quarkus CLIのインストール方法については、Quarkus CLIガイドをご参照ください。

Maven
mvn io.quarkus.platform:quarkus-maven-plugin:2.11.1.Final:create \
    -DprojectGroupId=org.acme \
    -DprojectArtifactId=spring-boot-properties-quickstart \
    -Dextensions="resteasy-reactive,spring-boot-properties" \
    -DnoCode
cd spring-boot-properties-quickstart

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

This command generates a project and imports the spring-boot-properties extension.

If you already have your Quarkus project configured, you can add the spring-boot-properties extension to your project by running the following command in your project base directory:

CLI
quarkus extension add 'spring-boot-properties'
Maven
./mvnw quarkus:add-extension -Dextensions="spring-boot-properties"
Gradle
./gradlew addExtension --extensions="spring-boot-properties"

This will add the following to your build file:

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

GreetingController

First, create a GreetingResource JAX-RS resource in the src/main/java/org/acme/spring/boot/properties/GreetingResource.java file that looks like:

package org.acme.spring.boot.properties;

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

@Path("/hello")
public class GreetingResource {

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

プロパティーの注入

Create a new class src/main/java/org/acme/spring/boot/properties/GreetingProperties.java with a message field:

package org.acme.spring.boot.properties;

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties("greeting")
public class GreetingProperties {

    public String text;
}

Here text field is public, but it could also be a private field with getter and setter or just a public getter in an interface. Because text does not have a default value it is considered required and unless it is defined in a configuration file (application.properties by default) your application will fail to start. Define this property in your src/main/resources/application.properties file:

# Your configuration properties
greeting.text = hello

Now modify GreetingResource to start using the GreetingProperties:

package org.acme.spring.boot.properties;

import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

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

    @Inject
    GreetingProperties properties;

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String hello() {
        return properties.text;
    }
}

テストを実行して、アプリケーションがまだ正常に機能していることを確認します。

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

Run the application in dev mode with:

CLI
quarkus dev
Maven
./mvnw quarkus:dev
Gradle
./gradlew --console=plain quarkusDev

Open your browser to http://localhost:8080/greeting.

設定ファイルの変更はすぐに反映されます。

いつものように、アプリケーションは以下の方法でパッケージ化されます。

CLI
quarkus build
Maven
./mvnw clean package
Gradle
./gradlew build

And executed using java -jar target/quarkus-app/quarkus-run.jar.

次のようにネイティブ実行可能ファイルを生成することもできます。

CLI
quarkus build --native
Maven
./mvnw package -Dnative
Gradle
./gradlew build -Dquarkus.package.type=native

デフォルト値

Now let’s add a suffix for a greeting for which we’ll set a default value.

Properties with default values can be configured in a configuration file just like any other property. However, the default value will be used if the property was not defined in a configuration file.

GreetingProperties クラスに新しいフィールドを追加してください。

package org.acme.spring.boot.properties;

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties("greeting")
public class GreetingProperties {

    public String text;

    public String suffix = "!";
}

そして、 GreetingResource とそのテスト GreetingResourceTest を更新します。

package org.acme.spring.boot.properties;

import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

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

    @Inject
    GreetingProperties properties;

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String hello() {
        return properties.text + properties.suffix;
    }
}
package org.acme.spring.boot.properties;

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!"));
    }
}

テストを実行して変更を確認します。

Optional values

Properties with optional values are the middle-ground between standard and properties with default values. While a missing property in a configuration file will not cause your application to fail, it will nevertheless not have a value set. We use java.util.Optional type to define such properties.

Add an optional name property to the GreetingProperties:

package org.acme.spring.boot.properties;

import java.util.Optional;

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties("greeting")
public class GreetingProperties {

    public String text;

    public String suffix = "!";

    public Optional<String> name;
}

そして、 GreetingResource とそのテスト GreetingResourceTest を更新します。

package org.acme.spring.boot.properties;

import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

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

    @Inject
    GreetingProperties properties;

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String hello() {
        return properties.text + ", " + properties.name.orElse("You") + properties.suffix;
    }
}
package org.acme.spring.boot.properties;

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, You!"));
    }
}

テストを実行して変更を確認します。

プロパティーのグループ化

Now we have three properties in our GreetingProperties class. While name could be considered more of a runtime property (and maybe could be passed as an HTTP query parameter in the future), text and suffix are used to define a message template. Let’s group these two properties in a separate inner class:

package org.acme.spring.boot.properties;

import java.util.Optional;

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties("greeting")
public class GreetingProperties {

    public Message message;

    public Optional<String> name;

    public static class Message {

        public String text;

        public String suffix = "!";
    }
}

Here Message properties class is defined as an inner class, but it could also be a top level class.

Having such property groups brings more structure to your configuration. This is especially useful when then number of properties grows.

Because of the additional class, our property names have changed. Let’s update the properties file and the GreetingResource class.

# Your configuration properties
greeting.message.text = hello
package org.acme.spring.boot.properties;

import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

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

    @Inject
    GreetingProperties properties;

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String hello() {
        return properties.message.text + ", " + properties.name.orElse("You") + properties.message.suffix;
    }
}