The English version of quarkus.io is the official project site. Translated sites are community supported on a best-effort basis.
返回指南目录

使用Spring Boot属性API访问应用程序属性

If you prefer to use Spring Boot @ConfigurationProperties annotated class to access application properties instead of @ConfigMapping or a MicroProfile @ConfigProperty approach, you can do that with this extension.

Spring Boot @ConfigurationProperties 有一些限制。例如,不支持 Map 注入。你可以考虑使用 将配置映射到对象

先决条件

完成这个指南,你需要:

  • 大概15分钟

  • 编辑器

  • 安装JDK 11以上版本并正确配置了 JAVA_HOME

  • Apache Maven 3.8.6

  • 如果你愿意的话,还可以选择使用Quarkus CLI

  • 如果你想构建原生可执行程序,可以选择安装Mandrel或者GraalVM,并正确配置(或者使用Docker在容器中进行构建)

解决方案

我们建议你按照下一节的说明逐步创建应用程序。然而,你也可以直接转到已完成的示例。

克隆 Git 仓库: git clone https://github.com/quarkusio/quarkus-quickstarts.git ,或者下载一个 存档

该解决方案位于 spring-boot-properties-quickstart 目录中。

创建Maven项目

首先,我们需要一个新的项目。使用以下命令创建一个新项目:

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

创建Grade项目,请添加 --gradle 或者 --gradle-kotlin-dsl 参数。

关于如何安装并使用Quarkus CLI的更多信息,请参考Quarkus CLI指南

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

创建Grade项目,请添加 -DbuildTool=gradle 或者 -DbuildTool=gradle-kotlin-dsl 参数。

该命令生成一个项目并导入了 spring-boot-properties 扩展。

如果你已经配置了你的Quarkus项目,你可以在项目的根目录下运行以下命令,并将 spring-boot-properties 扩展添加到你的项目中:

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

这会将以下内容添加到你的构建文件中:

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

GreetingController

首先,在 src/main/java/org/acme/spring/boot/properties/GreetingResource.java 文件中创建一个包含如下内容的 GreetingResource JAX-RS资源:

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

注入属性

创建一个包含消息字段的 src/main/java/org/acme/spring/boot/properties/GreetingProperties.java 类:

package org.acme.spring.boot.properties;

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

@ConfigurationProperties("greeting")
public class GreetingProperties {

    public String text;
}

在这里 text 字段是公共的,但它也可以是一个带有getter和setter的私有字段,或者只是一个接口中的公共getter。因为 text 没有默认值,所以它被认为是必需的,除非它被定义在一个配置文件中(默认为 application.properties ),否则你的应用程序将无法启动。在你的 src/main/resources/application.properties 文件中定义该属性:

# 你的属性配置
greeting.text = hello

现在,修改 GreetingResource 以使用 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;
    }
}

运行测试以验证应用程序是否仍能正常运行。

打包并运行该应用程序

在开发模式下运行该应用程序:

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

在你的浏览器中打开 http://localhost:8080/greeting 网页。

更改配置文件的内容将会立即得到反馈。

像往常一样,该应用程序能够使用以下方式进行打包:

CLI
quarkus build
Maven
./mvnw install
Gradle
./gradlew build

并使用 java -jar target/quarkus-app/quarkus-run.jar 命令运行该应用程序。

你也可以通过以下命令生成本地可执行文件:

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

默认值

现在,让我们为greeting 添加一个后缀,我们将为其设置一个默认值。

具有默认值的属性可以像其他属性一样在配置文件中被配置。然而,如果该属性没有在配置文件中被定义,则将使用默认值。

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

运行该测试以验证更改。

可选值

具有可选值的属性处于标准属性和具有默认值属性之间的中间地带。尽管在配置文件中缺少一个属性不会导致你的应用程序启动失败,但它还是没有被设置一个值。我们使用 java.util.Optional 类型来定义这种属性。

GreetingProperties 中添加一个可选的 name 属性:

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

运行该测试以验证更改。

分组属性

现在,在我们的 GreetingProperties 类中有三个属性。虽然 name 可以更多地被认为是运行时属性(也许在将来可以被作为HTTP查询参数进行传递),而 textsuffix 被用于定义一个消息模板。让我们将这两个属性作为一组放在一个独立的内部类中:

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

这里 Message 属性类被定义为一个内部类,但它也可以作为一个顶层类。

这样的属性分组可以为你的配置带来更加丰富的结构。当属性的数量增加时,这尤其有用。

因为有了额外的类,我们的属性名也发生了改变。让我们更新一下属性配置文件和 GreetingResource 类。

# 你的属性配置
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;
    }
}