Micronaut 使用 PropertySources 的外部化配置

2023-03-01 14:24 更新

在初始化 ApplicationContext 之前,可以將其他 PropertySource 實例添加到環(huán)境中。

初始化環(huán)境

 Java Groovy  Kotlin 
ApplicationContext applicationContext = ApplicationContext.run(
        PropertySource.of(
                "test",
                CollectionUtils.mapOf(
                    "micronaut.server.host", "foo",
                    "micronaut.server.port", 8080
                )
        ),
        "test", "android");
Environment environment = applicationContext.getEnvironment();

assertEquals(
        "foo",
        environment.getProperty("micronaut.server.host", String.class).orElse("localhost")
);
when:
ApplicationContext applicationContext = ApplicationContext.run(
        PropertySource.of(
                "test",
                [
                    "micronaut.server.host": "foo",
                    "micronaut.server.port": 8080
                ]
        ),
        "test", "android")
Environment environment = applicationContext.getEnvironment()

then:
"foo" == environment.getProperty("micronaut.server.host", String.class).orElse("localhost")
val applicationContext = ApplicationContext.run(
    PropertySource.of(
        "test",
        mapOf(
            "micronaut.server.host" to "foo",
            "micronaut.server.port" to 8080
        )
    ),
    "test", "android"
)
val environment = applicationContext.environment

assertEquals(
    "foo",
    environment.getProperty("micronaut.server.host", String::class.java).orElse("localhost")
)

PropertySource.of 方法可用于從值映射創(chuàng)建 PropertySource。

或者,可以通過創(chuàng)建包含對 PropertySourceLoader 類名的引用的 META-INF/services/io.micronaut.context.env.PropertySourceLoader 文件來注冊 PropertySourceLoader。

包含的 PropertySource 加載器

默認情況下,Micronaut 包含從給定位置和優(yōu)先級加載屬性的 PropertySourceLoader 實現(xiàn):

  1. 命令行參數(shù)

  2. 來自 SPRING_APPLICATION_JSON 的屬性(為了與 Spring 兼容)

  3. 來自 MICRONAUT_APPLICATION_JSON 的屬性

  4. Java 系統(tǒng)屬性

  5. 操作系統(tǒng)環(huán)境變量

  6. 配置文件從系統(tǒng)屬性“micronaut.config.files”或環(huán)境變量 MICRONAUT_CONFIG_FILES 中按順序加載。該值可以是以逗號分隔的路徑列表,最后一個文件具有優(yōu)先權。這些文件可以作為路徑從文件系統(tǒng)中引用,或者作為帶有 classpath: 前綴的類路徑引用。

  7. 來自 application-{environment}.{extension} 的環(huán)境特定屬性

  8. 來自 application.{extension} 的特定于應用程序的屬性

開箱即用地支持 .properties、.json、.yml。對于 Groovy 用戶,也支持 .groovy。

請注意,如果您想完全控制應用程序從何處加載配置,您可以通過在啟動應用程序時調(diào)用 ApplicationContextBuilder 接口的 enableDefaultPropertySources(false) 方法來禁用上面列出的默認 PropertySourceLoader 實現(xiàn)。

在這種情況下,只會使用您通過 ApplicationContextBuilder 接口的 propertySources(..) 方法添加的顯式 PropertySource 實例。

通過命令行提供配置

可以使用 Gradle 或我們的 Maven 插件在命令行中提供配置。例如:

Gradle

$ ./gradlew run --args="-endpoints.health.enabled=true -config.property=test"

Maven

$ ./mvnw mn:run -Dmn.appArgs="-endpoints.health.enabled=true -config.property=test"

為了使配置成為上下文的一部分,必須將 main 方法中的參數(shù)傳遞給上下文構建器。例如:

import io.micronaut.runtime.Micronaut;

public class Application {

    public static void main(String[] args) {
        Micronaut.run(Application.class, args); // passing args
    }
}

秘密和敏感配置

重要的是要注意,不建議將敏感配置(例如密碼和令牌)存儲在可能被檢入源代碼控制系統(tǒng)的配置文件中。

最好使用外部秘密管理器系統(tǒng)(這里有很多選項,許多由云提供商提供)或在應用程序部署期間設置的環(huán)境變量,而不是從應用程序代碼中完全外部化敏感配置。您還可以使用屬性占位符(請參閱下一節(jié))來自定義要使用的環(huán)境變量的名稱并提供默認值:

使用屬性值占位符定義安全配置

 Properties Yaml  Toml  Groovy  Hocon  JSON 
datasources.default.url=${JDBC_URL:`jdbc:mysql://localhost:3306/db`}
datasources.default.username=${JDBC_USER:root}
datasources.default.password=${JDBC_PASSWORD:}
datasources.default.dialect=MYSQL
datasources.default.driverClassName=${JDBC_DRIVER:com.mysql.cj.jdbc.Driver}
datasources:
  default:
    url: ${JDBC_URL:`jdbc:mysql://localhost:3306/db`}
    username: ${JDBC_USER:root}
    password: ${JDBC_PASSWORD:}
    dialect: MYSQL
    driverClassName: ${JDBC_DRIVER:com.mysql.cj.jdbc.Driver}
[datasources]
  [datasources.default]
    url="${JDBC_URL:`jdbc:mysql://localhost:3306/db`}"
    username="${JDBC_USER:root}"
    password="${JDBC_PASSWORD:}"
    dialect="MYSQL"
    driverClassName="${JDBC_DRIVER:com.mysql.cj.jdbc.Driver}"
datasources {
  'default' {
    url = "${JDBC_URL:`jdbc:mysql://localhost:3306/db`}"
    username = "${JDBC_USER:root}"
    password = "${JDBC_PASSWORD:}"
    dialect = "MYSQL"
    driverClassName = "${JDBC_DRIVER:com.mysql.cj.jdbc.Driver}"
  }
}
{
  datasources {
    default {
      url = "${JDBC_URL:`jdbc:mysql://localhost:3306/db`}"
      username = "${JDBC_USER:root}"
      password = "${JDBC_PASSWORD:}"
      dialect = "MYSQL"
      driverClassName = "${JDBC_DRIVER:com.mysql.cj.jdbc.Driver}"
    }
  }
}
{
  "datasources": {
    "default": {
      "url": "${JDBC_URL:`jdbc:mysql://localhost:3306/db`}",
      "username": "${JDBC_USER:root}",
      "password": "${JDBC_PASSWORD:}",
      "dialect": "MYSQL",
      "driverClassName": "${JDBC_DRIVER:com.mysql.cj.jdbc.Driver}"
    }
  }
}

為了安全地將配置外部化,請考慮使用 Micronaut 支持的秘密管理器系統(tǒng),例如:

屬性值占位符

如前一節(jié)所述,Micronaut 包含一個屬性占位符語法,用于在配置值中和任何 Micronaut 注釋中引用配置屬性。

也可以通過 PropertyPlaceholderResolver 接口以編程方式使用。

基本語法是將對屬性的引用包裝在 ${... } 中。例如:

定義屬性占位符

 Properties Yaml  Toml  Groovy  Hocom  JSON 
myapp.endpoint=http://${micronaut.server.host}:${micronaut.server.port}/foo
myapp:
  endpoint: http://${micronaut.server.host}:${micronaut.server.port}/foo
[myapp]
  endpoint="http://${micronaut.server.host}:${micronaut.server.port}/foo"
myapp {
  endpoint = "http://${micronaut.server.host}:${micronaut.server.port}/foo"
}
{
  myapp {
    endpoint = "http://${micronaut.server.host}:${micronaut.server.port}/foo"
  }
}
{
  "myapp": {
    "endpoint": "http://${micronaut.server.host}:${micronaut.server.port}/foo"
  }
}

上面的示例嵌入了對 micronaut.server.host 和 micronaut.server.port 屬性的引用。

您可以通過在 : 字符后定義一個值來指定默認值。例如:

使用默認值

 Properties Yaml  Toml  Groovy  Hocom  JSON 
myapp.endpoint=http://${micronaut.server.host:localhost}:${micronaut.server.port:8080}/foo
myapp:
  endpoint: http://${micronaut.server.host:localhost}:${micronaut.server.port:8080}/foo
[myapp]
  endpoint="http://${micronaut.server.host:localhost}:${micronaut.server.port:8080}/foo"
myapp {
  endpoint = "http://${micronaut.server.host:localhost}:${micronaut.server.port:8080}/foo"
}
{
  myapp {
    endpoint = "http://${micronaut.server.host:localhost}:${micronaut.server.port:8080}/foo"
  }
}
{
  "myapp": {
    "endpoint": "http://${micronaut.server.host:localhost}:${micronaut.server.port:8080}/foo"
  }
}

如果沒有找到值(而不是拋出異常),上面的示例默認為 localhost 和端口 8080。請注意,如果默認值包含 : 字符,則必須使用反引號對其進行轉(zhuǎn)義:

使用反引號

 Properties Yaml  Toml  Groovy  Hocom  JSON 
myapp.endpoint=${server.address:`http://localhost:8080`}/foo
myapp:
  endpoint: ${server.address:`http://localhost:8080`}/foo
[myapp]
  endpoint="${server.address:`http://localhost:8080`}/foo"
myapp {
  endpoint = "${server.address:`http://localhost:8080`}/foo"
}
{
  myapp {
    endpoint = "${server.address:`http://localhost:8080`}/foo"
  }
}
{
  "myapp": {
    "endpoint": "${server.address:`http://localhost:8080`}/foo"
  }
}

上面的示例查找 server.address 屬性并默認為 http://localhost:8080。這個默認值用反引號轉(zhuǎn)義,因為它有一個 : 字符。

屬性值綁定

請注意,在代碼或占位符值中放置引用時,這些屬性引用應采用 kebab 大小寫(小寫和連字符分隔)。例如,使用 micronaut.server.default-charset 而不是 micronaut.server.defaultCharset。

Micronaut 仍然允許在配置中指定后者,但將屬性規(guī)范化為 kebab case 形式,以優(yōu)化內(nèi)存消耗并降低解析屬性時的復雜性。下表總結了如何從不同來源規(guī)范化屬性:

表 1. 屬性值規(guī)范化
配置值 結果屬性 屬性來源

myApp.myStuff

my-app.my-stuff

Properties, YAML etc.

my-app.myStuff

my-app.my-stuff

Properties, YAML etc.

myApp.my-stuff

my-app.my-stuff

Properties, YAML etc.

MYAPP_MYSTUFF

myapp.mystuffmyapp-mystuff

Environment Variable

MY_APP_MY_STUFF

my.app.my.stuffmy.app.my-stuffmy.app-my.stuffmy.app-my-stuffmy-app.my.stuffmy-app.my-stuffmy-app-my.stuffmy-app-my-stuff

Environment Variable

環(huán)境變量經(jīng)過特殊處理以提供更大的靈活性。請注意,無法使用駝峰式大小寫來引用環(huán)境變量。

由于生成的屬性數(shù)量根據(jù)環(huán)境變量中_字符的數(shù)量呈指數(shù)增長,因此如果具有多個下劃線的環(huán)境變量數(shù)量較多,建議細化配置中包含的環(huán)境變量(如果有)。

要控制環(huán)境屬性如何參與配置,請在 Micronaut 構建器上調(diào)用相應的方法。

應用類

 Java  Groovy Kotlin 
import io.micronaut.runtime.Micronaut;

public class Application {

    public static void main(String[] args) {
        Micronaut.build(args)
                .mainClass(Application.class)
                .environmentPropertySource(false)
                //or
                .environmentVariableIncludes("THIS_ENV_ONLY")
                //or
                .environmentVariableExcludes("EXCLUDED_ENV")
                .start();
    }
}
import io.micronaut.runtime.Micronaut

class Application {

    static void main(String[] args) {
        Micronaut.build()
                .mainClass(Application)
                .environmentPropertySource(false)
                //or
                .environmentVariableIncludes("THIS_ENV_ONLY")
                //or
                .environmentVariableExcludes("EXCLUDED_ENV")
                .start()
    }
}
import io.micronaut.runtime.Micronaut

object Application {

    @JvmStatic
    fun main(args: Array<String>) {
        Micronaut.build(null)
                .mainClass(Application::class.java)
                .environmentPropertySource(false)
                //or
                .environmentVariableIncludes("THIS_ENV_ONLY")
                //or
                .environmentVariableExcludes("EXCLUDED_ENV")
                .start()
    }
}

上面的配置對屬性占位符沒有任何影響。無論是否禁用環(huán)境配置,或者即使明確排除特定屬性,仍然可以在占位符中引用環(huán)境變量。

使用隨機屬性

您可以通過使用以下屬性來使用隨機值。這些可以在配置文件中用作變量,如下所示。

 Properties Yaml  Toml  Groovy  Hocon  JSON 
micronaut.application.name=myapplication
micronaut.application.instance.id=${random.shortuuid}
micronaut:
  application:
    name: myapplication
    instance:
      id: ${random.shortuuid}
[micronaut]
  [micronaut.application]
    name="myapplication"
    [micronaut.application.instance]
      id="${random.shortuuid}"
micronaut {
  application {
    name = "myapplication"
    instance {
      id = "${random.shortuuid}"
    }
  }
}
{
  micronaut {
    application {
      name = "myapplication"
      instance {
        id = "${random.shortuuid}"
      }
    }
  }
}
{
  "micronaut": {
    "application": {
      "name": "myapplication",
      "instance": {
        "id": "${random.shortuuid}"
      }
    }
  }
}
表 2. 隨機值
屬性

random.port

一個可用的隨機端口號

random.int

隨機整數(shù)

random.integer

隨機整數(shù)

random.long

隨機長整數(shù)

random.float

隨機浮點數(shù)

random.shortuuid

長度僅為 10 個字符的隨機 UUID(注意:由于這不是完整的 UUID,可能會發(fā)生沖突)

random.uuid

帶破折號的隨機 UUID

random.uuid2

沒有破折號的隨機 UUID

random.int、random.integer、random.long 和 random.float 屬性支持范圍后綴,其語法為以下之一:

  • (max) 其中 max 是一個獨占值

  • [min,max] 其中 min 是包容性的,max 是獨占的。

 Properties Yaml  Toml   Groovy Hocon  JSON 
instance.id=${random.int[5,10]}
instance.count=${random.int(5)}
instance:
  id: ${random.int[5,10]}
  count: ${random.int(5)}
[instance]
  id="${random.int[5,10]}"
  count="${random.int(5)}"
instance {
  id = "${random.int[5,10]}"
  count = "${random.int(5)}"
}
{
  instance {
    id = "${random.int[5,10]}"
    count = "${random.int(5)}"
  }
}
{
  "instance": {
    "id": "${random.int[5,10]}",
    "count": "${random.int(5)}"
  }
}

該范圍也可以從負到正變化。

快速失敗屬性注入

對于注入所需屬性的 bean,在請求 bean 之前不會發(fā)生注入和潛在的失敗。要在啟動時驗證屬性是否存在并且可以注入,可以使用 @Context 對 bean 進行注釋。上下文范圍的 beans 在啟動時注入,如果缺少任何必需的屬性或無法轉(zhuǎn)換為所需的類型,則啟動將失敗。

建議謹慎使用此功能以確??焖賳印?/p>


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號