应用配置支持

本文介绍 Spring Cloud Azure 应用程序配置 库。 此库从 Azure 应用程序配置 服务加载配置和功能标志。 该库生成 PropertySource 抽象以匹配 Spring 环境已经生成的抽象,例如环境变量、命令行配置、本地配置文件等。

Spring 是 VMware 开发的开源应用程序框架,它提供简化的模块化方法来创建 Java 应用程序。 Spring Cloud Azure 是一个开源项目,提供 Spring 与 Azure 服务的无缝集成。

先决条件

设置应用程序配置存储

使用以下命令创建Azure 应用程序配置存储:

az appconfig create \
    --resource-group <your-resource-group> \
    --name <name-of-your-new-store> \
    --sku Standard

此命令将创建新的空配置存储。 可以使用以下导入命令上传配置:

az appconfig kv import \
    --name <name-of-your-new-store> \
    --source file \
    --path <location-of-your-properties-file> \
    --format properties \
    --prefix /application/

在加载配置之前确认配置。 可以通过将格式更改为 YAML 来上传 YAML 文件。 前缀字段很重要,因为它是客户端库加载的默认前缀。

库使用情况

若要在应用程序中使用该功能,可以将其生成为 Spring Boot 应用程序。 添加依赖项的最方便方法是使用 Spring Boot 初学者 com.azure.spring:spring-cloud-azure-starter-appconfiguration-config。 以下示例pom.xml文件使用Azure 应用程序配置:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>{spring-boot-version}</version>
    <relativePath />
</parent>

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>com.azure.spring</groupId>
      <artifactId>spring-cloud-azure-dependencies</artifactId>
      <version>5.12.0</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>com.azure.spring</groupId>
        <artifactId>spring-cloud-azure-starter-appconfiguration-config</artifactId>
    </dependency>
</dependencies>
<build>
    <plugins>
           <plugin>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-maven-plugin</artifactId>
           </plugin>
    </plugins>
</build>

注意

如果使用 Spring Boot 2.x,请确保将 spring-cloud-azure-dependencies 版本设置为 4.18.0。 有关用于此 BOM 的版本的详细信息,请参阅 我应使用哪个版本的 Spring Cloud Azure。

以下示例演示了使用 应用程序配置 的基本 Spring Boot 应用程序:

@SpringBootApplication
@RestController
public class Application {

    @RequestMapping("/")
    public String home() {
        return "Hello World!";
    }

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

对于此示例, bootstrap.properties 文件包含以下行:

spring.cloud.azure.appconfiguration.stores[0].connection-string=${CONFIG_STORE_CONNECTION_STRING}

CONFIG_STORE_CONNECTION_STRING是一个环境变量,其中包含Azure 应用程序配置应用商店的连接字符串。 可以使用以下命令访问连接字符串:

az appconfig credential list --name <name-of-your-store>

默认情况下,如果未设置任何配置,则以默认标签开头 /application/ 的配置将加载为默认标签 (No Label) ,除非设置了 Spring Profile,在这种情况下,默认标签为 Spring Profile。 由于存储为空,因此不会加载任何配置,但仍会生成Azure 应用程序配置属性源。

将创建一个名为 /application/https://<name-of-your-store>.azconfig.io/ 的属性源,其中包含该存储的属性。 请求中使用的标签将追加到名称的末尾。 如果未设置标签,则字符 \0 显示为空白。

加载配置

该库支持加载一个或多个应用程序配置存储。 在多个存储区中复制密钥的情况下,加载所有存储会导致加载优先级最高的存储配置。 最后一场胜利。 以下示例演示了此过程:

spring.cloud.azure.appconfiguration.stores[0].connection-string=[first-store-connection-string]
spring.cloud.azure.appconfiguration.stores[1].connection-string=[second-store-connection-string]

在此示例中,如果第一和第二个存储区具有相同的配置,则第二个存储区中的配置具有最高优先级,最后一个存储将获胜。

注意

可以使用与其他任何 Spring Configuration 一样Azure 应用程序配置设置。 有关详细信息,请参阅 Spring Boot 文档或快速入门中的核心功能:使用 Azure 应用程序配置 创建 Java Spring 应用。

选择配置

配置按键和标签加载。 默认情况下,加载以密钥 /application/ 开头的配置。 默认标签为 ${spring.profiles.active}. 如果未 ${spring.profiles.active} 设置,则会加载具有标签的配置 null 。 标签null显示在(No Label)Azure 门户中。

可以通过选择不同的键和标签筛选器来配置加载的配置,如以下示例所示:

spring.cloud.azure.appconfiguration.stores[0].selects[0].key-filter=[my-key]
spring.cloud.azure.appconfiguration.stores[0].selects[0].label-filter=[my-label]

key-filter 属性支持以下筛选器:

键筛选器 效果
* 匹配任何键。
abc 与名为 .. 的 abc键匹配。
abc* 匹配以 abc 开头的密钥名称。
abc,xyz 匹配密钥名称 abcxyz。 限制为五个逗号分隔的值。

label-filter 属性支持以下筛选器:

标签 说明
* 匹配任何标签,包括 \0
\0 null匹配显示在Azure 门户中的标签(No Label)
1.0.0 完全匹配标签 1.0.0
1.0.* 匹配以 1.0.* 开头的标签。
,1.0.0 匹配标签 null1.0.0。 限制为五个逗号分隔的值。

如果使用 YAML 和标签筛选器,并且需要从 null开头,则标签筛选器需要用单引号括起来,如以下示例所示:

spring:
  cloud:
    azure:
      appconfiguration:
        stores:
        - selects:
          - label-filter: ',1.0.0'

注意

不能在筛选器中与*,合并。 在这种情况下,需要使用其他选择值。

Spring 配置文件

默认情况下, spring.profiles.active 设置为所有所选配置的默认值 label-filter 。 可以使用 label-filter.. 可以使用 <a0/> 中的 label-filter Spring Profiles,如以下示例所示:

spring.cloud.azure.appconfiguration.stores[0].selects[0].label-filter=,${spring.profiles.active}
spring.cloud.azure.appconfiguration.stores[0].selects[1].label-filter=${spring.profiles.active}_local

首先 label-filter,加载标签 null 的所有配置,后跟与 Spring Profiles 匹配的所有配置。 Spring Profiles 优先于 null 配置,因为它们位于末尾。

第二 label-filter个字符串 _local 追加到 Spring Profiles 的末尾,但仅追加到最后一个 Spring Profile。

禁用的存储

使用配置 spring.cloud.azure.appconfiguration.enabled,可以禁用所有配置存储的加载。 使用 spring.cloud.azure.appconfiguration.stores[0].enabled 配置,可以禁用单个存储。

除了禁用存储之外,还可以配置存储区,以便在存储无法加载时被禁用。 对于此配置,请使用 spring.cloud.azure.appconfiguration.stores[0].fail-fastfail-fast如果通过将其设置为false禁用,则会导致应用程序存储被禁用,RuntimeException且未加载任何配置。 如果在启动时禁用配置存储,则刷新时不会检查更改。 此外,如果更新配置,则不会尝试从中加载值。

如果在刷新检查或尝试重新加载配置期间发生错误RuntimeException,则刷新尝试将结束,并在传递后refresh-interval重试。

身份验证

该库支持 Azure 标识库支持的所有形式的标识。 可以通过配置对连接字符串和托管标识进行身份验证。

连接字符串

通过连接字符串进行身份验证是设置的最简单形式。 可以使用以下命令访问商店的连接字符串:

az appconfig credential list --name <name-of-your-store>

然后,可以将属性spring.cloud.azure.appconfiguration.stores[0].connection-string设置为连接字符串。 强烈建议将本地配置文件中的连接字符串设置为映射到环境变量的占位符值。 使用此方法,可以避免将连接字符串添加到源代码管理。

Spring Cloud Azure 配置

可以使用 Spring Cloud Azure 配置 来配置库。 可以使用以下属性配置库:

spring.cloud.azure.appconfiguration.stores[0].endpoint= <URI-of-your-configuration-store>

仅设置终结点时,客户端库使用 DefaultAzureCredential 进行身份验证。 使用以下 DefaultAzureCredential 方法进行身份验证:

  • 环境凭据
  • 托管标识凭据
  • Azure 开发人员 CLI 凭据
  • IntelliJ 凭据
  • Azure CLI 凭据
  • Azure PowerShell 凭据

需要分配标识(例如系统分配的标识)来读取配置。 可以使用以下命令创建此分配:

az role assignment create \
    --role "App Configuration Data Reader" \
    --assignee <your-client-ID> \
    --scope /subscriptions/<your-subscription>/resourceGroups/<your-stores-resource-group>/providers/Microsoft.AppConfiguration/configurationStores/<name-of-your-configuration-store>

注意

每个终结点只能定义一种身份验证方法:连接字符串、用户分配的标识或令牌凭据。 如果需要混合和匹配,则可以用于 ConfigurationClientCustomizer 修改使用其他方法的存储区。

异地复制

该库支持Azure 应用程序配置的异地副本 (replica)功能。 使用此功能可将数据副本 (replica)到其他位置。 此功能可用于高可用性和灾难恢复。

你创建的每个副本 (replica)都有一个专用终结点。 如果应用程序位于多个地理位置,则可以将应用程序在某个位置的每项部署更新为连接到更靠近该位置的副本,这有助于最大限度地减少应用程序和应用程序配置之间的网络延迟。 由于每个副本 (replica)都有其单独的请求配额,因此此设置还有助于应用程序的可伸缩性,同时它扩展到多区域分布式服务。

如果库观察到以下任一情况,则可能会发生故障转移:

  • 从终结点接收服务不可用状态代码(HTTP 500 或更高版本)的响应。
  • 遇到网络连接问题。
  • 请求受到限制(HTTP 状态代码 429)。

使用异地副本 (replica)创建配置存储

若要创建配置存储副本 (replica),可以使用 Azure CLI 或 Azure 门户。 以下示例使用 Azure CLI 在美国东部 2 区域中创建副本 (replica):

az appconfig replica create --location --name --store-name [--resource-group]

使用配置存储副本 (replica)

创建副本 (replica)后,可以在应用程序中使用它。 与源存储一样,可以使用 Microsoft Entra ID 或连接字符串连接到副本 (replica)。

若要使用 Microsoft Entra ID 连接到副本 (replica),需要列出endpoints配置存储实例,如以下示例所示:

spring.cloud.azure.appconfiguration.stores[0].endpoints[0]=[your primary store endpoint]
spring.cloud.azure.appconfiguration.stores[0].endpoints[1]=[your replica store endpoint]

可以列出与副本 (replica)一样多的终结点。 该库尝试按照终结点列出的顺序连接到终结点。 如果库无法连接到副本 (replica),它将尝试列表中的下一个库。 经过一段时间后,库会尝试重新连接到首选终结点。

密钥值

Azure 应用程序配置支持多种类型的键值,其中一些键值内置了特殊功能。 Azure 应用程序配置内置支持 JSON 内容类型、Spring 占位符和密钥库引用。

占位符

该库支持具有 ${}-style 环境占位符的配置。 使用占位符引用Azure 应用程序配置键时,请从引用中删除前缀。 例如, /application/config.message 引用为 ${config.message}.

注意

要移除的前缀与值 spring.cloud.azure.appconfiguration.stores[0].selects[0].key-filter匹配。

JSON

具有内容类型 application/json 的配置将作为 JSON 对象进行处理。 使用此功能可将一个配置映射到内部 @ConfigurationProperties的复杂对象。 例如,请考虑具有以下值的 JSON 键 /application/config.colors

{
 "Red": {
  "value": [255, 0, 0]
 },
 "Blue": {
  "value": [0, 255, 0]
 },
 "Green": {
  "value": [0, 0, 255]
 }
}

此键映射到以下代码:

@ConfigurationProperties(prefix = "config")
public class MyConfigurations {

    private Map<String, Color> colors;

}

密钥保管库引用

Azure 应用程序配置及其库支持引用存储在密钥库中的机密。 在应用程序配置中,可以使用映射到存储在密钥库中的机密的值创建密钥。 机密安全地存储在密钥库中,但可以在加载机密后以与任何其他配置相同的方式进行访问。

应用程序使用客户端提供程序检索密钥库引用,就像在应用程序配置中存储的任何其他密钥一样。 由于客户端将密钥识别为密钥库引用,因此它们具有唯一的内容类型,客户端连接到密钥库以检索其值。

注意

密钥库一次只允许检索机密,因此每个密钥库引用存储在应用程序配置中会导致对密钥库进行拉取。

创建密钥库引用

可以通过转到“配置资源管理器>创建密钥库引用”,在Azure 门户中创建>密钥库引用。 然后,可以从你有权访问的任何密钥库中选择一个要引用的机密。 还可以从“输入”选项卡创建任意密钥库引用。在Azure 门户中,输入有效的 URI。

还可以使用以下命令通过 Azure CLI 创建密钥库引用:

az appconfig kv set-keyvault \
    --name <name-of-your-store> \
    --key <key-name> \
    --secret-identifier <URI-to-your-secret>

可以通过 Azure CLI 创建任何机密标识符。 机密标识符只需要版本节是可选的格式 {vault}/{collection}/{name}/{version?}

使用密钥库引用

可以使用 Spring Cloud Azure 配置 来配置库。 可以使用用于连接到 应用程序配置 的凭据连接到 Azure 密钥库。

解析非密钥库机密

应用程序配置库提供了一种方法,用于本地解析没有与之关联的密钥库的机密。 此解决方法是通过 KeyVaultSecretProvider.. KeyVaultSecretProvider如果未为密钥库引用提供 aTokenCredential,则会调用它。 提供了密钥库引用的 URI,返回的值将成为机密的值。

警告

使用 KeyVaultSecretProvider 替代系统分配的托管标识的自动使用。 若要同时使用这两者,需要使用 KeyVaultCredentialProvider 和返回 null 需要解析的 URI。

public class MySecretProvider implements KeyVaultSecretProvider {

    @Override
    public String getSecret(String uri) {
        ...
    }

}

特色管理

功能管理为 Spring Boot 应用程序提供了动态访问内容的方法。 功能管理具有各种功能,例如以下功能:

  • 可启用或禁用内容的功能标志
  • 显示内容时用于定位的功能筛选器
  • 自定义功能筛选器
  • 用于动态启用终结点的功能门

可以通过以下配置启用功能标志:

spring.cloud.azure.appconfiguration.stores[0].feature-flags.enabled= true

已启用的功能标志将加载到具有前缀 feature-management的 Spring 配置系统中。 还可以在本地配置文件中注册功能标志。 有关详细信息,请参阅 功能标志声明 部分。

使用功能管理的最简单方法是使用 spring-cloud-azure-feature-managementspring-cloud-azure-feature-management-web 。 这两个库之间的区别在于spring-cloud-azure-feature-management-web依赖于库和spring-webmvc库来添加更多功能,例如功能门spring-web

可以使用键/标签筛选器启用功能标志。 默认情况下,分配了一个 null 标签(被视为 (No Label))。 可以通过设置标签筛选器来配置加载的功能标志,如以下示例所示:

spring.cloud.azure.appconfiguration.stores[0].feature-flags.selects[0].key-filter=A*
spring.cloud.azure.appconfiguration.stores[0].feature-flags.selects[0].label-filter= dev

功能管理基础知识

功能标志

功能标志由两个部分组成:一个名称和一个用于打开该功能的功能筛选器列表。 功能标志可以具有布尔状态为 on/off,也可以具有功能筛选器列表。 功能标志评估功能筛选器,直到返回 true。 如果未返回 true任何功能筛选器,则功能标志返回 false

功能筛选器

功能筛选器定义何时应启用功能的方案。 功能筛选器是同步评估的。

功能管理库附带了四个预定义筛选器:AlwaysOnFilterPercentageFilterTimeWindowFilterTargetingFilter

可以创建自定义功能筛选器。 例如,可以使用功能筛选器为使用 Microsoft Edge 浏览器的客户提供自定义体验。 例如,可以自定义此功能筛选器中的功能,以显示 Microsoft Edge 浏览器受众的特定标头。

功能标志声明

功能管理库支持Azure 应用程序配置以及作为功能标志源的application.yml或bootstrap.yml。 下面是用于在 application.yml 文件中设置功能标志的格式示例:

feature-management:
  feature-t: false
  feature-u:
    enabled-for:
    - name: Random
  feature-v:
    enabled-for:
    - name: TimeWindowFilter
      parameters:
        Start: "Wed, 01 May 2019 13:59:59 GMT"
        End: "Mon, 01 July 2019 00:00:00 GMT"
  feature-w:
    evaluate: false
    enabled-for:
    - name: AlwaysOnFilter

此示例具有以下功能标志:

  • feature-t 设置为 false。 此设置始终返回功能标志的值。
  • feature-u 用于功能筛选器。 这些筛选器在属性下 enabled-for 定义。 在这种情况下, feature-u 调用了一个功能筛选器 Random,它不需要任何配置,因此只需要 name 属性。
  • feature-v 指定名为 TimeWindowFilter.. 的功能筛选器。 此功能筛选器可以传递参数以用作配置。 在此示例中,一个 TimeWindowFilter在功能处于活动状态的开始和结束时间中传递。
  • feature-w用于始终计算结果为 true.AlwaysOnFilter. 该 evaluate 字段用于停止对特征筛选器的计算,并导致功能筛选器始终返回 false

评估功能标志

spring-cloud-azure-feature-management 库提供 FeatureManager 以确定功能标志是否已启用。 FeatureManager提供检查标志状态的异步方法。

spring-cloud-azure-feature-management-web,以及提供 FeatureManager,它 FeatureManagerSnapshot缓存以前评估的功能标志 @RequestScope 的状态,以确保所有请求返回相同的值。 此外,Web 库提供 @FeatureGate,它可以阻止或将 Web 请求重定向到不同的终结点。

功能标志检查

FeatureManager@Bean是可以@Autowired或注入到@Component类型对象中。 FeatureManager 具有一个方法 isEnabled ,当传递功能标志的名称时,返回其状态。

@Autowired
FeatureManager featureManager;

if (featureManager.isEnabled("feature-t")) {
    // Do Something
}

注意

FeatureManger还有一个调用isEnabledAsyncisEnabled异步版本。

如果尚未配置功能管理或功能标志不存在, isEnabled 则始终返回 false。 如果现有功能标志配置了未知功能筛选器,则会引发一个 FilterNotFoundException 。 可以通过配置fail-fastfalse此行为来更改此行为以返回false。 下表描述了 fail-fast

名称 说明 需要 默认
spring.cloud.azure.feature.management.fail-fast 如果发生异常,则会引发 a RuntimeException 。 如果此属性设置为 false,则 isEnabled 返回 false true

结果缓存@RequestScope的唯一区别FeatureManagerSnapshot在于 FeatureManager

功能门

使用功能管理 Web 库,可以要求启用给定功能才能执行终结点。 可以使用批注设置此要求 @FeatureGate ,如以下示例所示:

@GetMapping("/featureT")
@FeatureGate(feature = "feature-t")
@ResponseBody
public String featureT() {
    ...
}

如果启用了“feature-t”, featureT 则只能访问终结点。

禁用的操作处理

当终结点被阻止时,将调用它指定的功能。 DisabledFeaturesHandler 默认情况下,返回 HTTP 404。 可以通过实现 DisabledFeaturesHandler来替代此行为,如以下示例所示:

@Component
public class MyDisabledFeaturesHandler implements DisabledFeaturesHandler {

    @Override
    public HttpServletResponse handleDisabledFeatures(HttpServletRequest request, HttpServletResponse response) {
        ...
        return response;
    }

}
路由

某些路由可能会公开受功能限制的应用程序功能。 如果禁用了某个功能,可以将这些路由重定向到另一终结点,如以下示例所示:

@GetMapping("/featureT")
@FeatureGate(feature = "feature-t" fallback= "/oldEndpoint")
@ResponseBody
public String featureT() {
    ...
}

@GetMapping("/oldEndpoint")
@ResponseBody
public String oldEndpoint() {
    ...
}

内置功能筛选器

包附带 spring-cloud-azure-feature-management 了一些功能筛选器。 这些功能筛选器不会自动添加,但你可以在一个 @Configuration中设置它们。

AlwaysOnFilter

此筛选器始终返回 true。 有关用法示例,请参阅 功能标志声明 部分。

PercentageFilter

每次用户发出请求时,评估 PercentageFilter 都可以返回不同的结果。 可以使用可缓存每个用户的功能标志结果的不一 FeatureManagementSnapshot致来规避此不一致。 此功能可确保用户具有一致的体验,即使用户必须重新发送请求。

feature-management:
  feature-v:
    enabled-for:
    - name: PercentageFilter
      parameters:
        Value: 50

TimeWindowFilter

此筛选器提供基于时间窗口启用功能的功能。 如果仅 End指定,则该功能将一直考虑在该时间之前。 如果仅 Start指定,则该功能将在该时间后的所有时间点上考虑。 如果同时指定这两个功能,则该功能在两次之间被视为有效。

feature-management:
  feature-v:
    enabled-for:
    - name: TimeWindowFilter
      parameters:
        Start: "Wed, 01 May 2019 13:59:59 GMT",
        End: "Mon, 01 July 2019 00:00:00 GMT"

TargetingFilter

此筛选器提供为目标受众启用功能的功能。 有关目标的深入说明,请参阅 “目标”部分 。 筛选器参数包括一个受众对象,该对象描述用户、组和应有权访问该功能的用户群的默认百分比。 对于目标受众中列出的每个组对象,需要一个百分比,该百分比定义有权访问该功能的组成员的百分比。 以下情况下,用户已启用该功能:

  • 用户直接在用户部分中指定。
  • 用户包含在任何组推出中的百分比中。
  • 用户属于默认推出百分比。
feature-management: 
  target:
    enabled-for:
    - name: targetingFilter
      parameters:
        users:
        - Jeff
        - Alicia
        groups:
        - name: Ring0
          rollout-percentage: 100
        - name: Ring1
          rolloutPercentage: 100
        default-rollout-percentage: 50

自定义功能筛选器

创建自定义功能筛选器提供了一种基于所定义条件启用功能的方法。 若要创建自定义功能筛选器,必须实现 FeatureFilter 接口。 FeatureFilter 具有单个方法 evaluate。 当某个功能指定可以使用功能筛选器启用该功能时,将调用该方法 evaluate 。 如果 evaluate 返回 true,则表示应启用该功能。 如果返回 false,它将继续评估功能筛选器,直到返回 true。 如果所有筛选器都返回 false,则该功能处于关闭状态。

特征筛选器定义为 Spring Beans,因此它们在一个@Configuration中定义@Component或定义。

@Component("Random")
public class Random implements FeatureFilter {

    @Override
    public boolean evaluate(FeatureFilterEvaluationContext context) {
        double chance = Double.valueOf((String) context.getParameters().get("chance"));
        return Math.random() > chance / 100;
    }

}

参数化功能筛选器

某些功能筛选器需要参数来确定是否应启用某个功能。 例如,浏览器功能筛选器可能会为一组特定浏览器打开一项功能。 你可能希望为 Microsoft Edge 和 Chrome 浏览器启用一项功能,但不希望为 Firefox 启用此功能。 若要设置这种情况,可以设计功能筛选器以预期参数。 这些参数将在功能配置和代码中指定,可通过参数evaluate访问FeatureFilterEvaluationContextFeatureFilterEvaluationContext 具有一个属性 parameters,即一个 HashMap<String, Object>

目标设定

目标定位是一种功能管理策略,使开发人员能够逐步向其用户群推出新功能。 该策略建立在面向一组称为目标受众的用户的概念之上。 受众由特定用户、组和占整个用户群的指定百分比的人数组成。 受众中包含的组可以进一步细分为其成员总数的百分比。

以下步骤演示了新“Beta”功能的渐进式推出示例:

  1. 个人用户 Jeff 和 Alicia 有权访问 Beta 版。
  2. 另一个用户 Mark 要求加入并包含在内。
  3. Beta 版中包含 20% 的名为“Ring1”用户的组。
  4. beta 版中包含的“Ring1”用户数高达 100%。
  5. beta 版中包含 5% 的用户群。
  6. 推出百分比将提升到 100%,该功能已完全推出。

此用于推出功能的策略通过包含 TargetingFilter 的功能筛选器内置到库中。

在应用程序中定位

示例项目中提供了使用目标功能筛选器的示例 Web 应用程序。

若要开始在应用程序中使用 TargetingFilter ,必须将其添加为与任何其他功能筛选器一 @Bean 样。 TargetingFilter 依赖于另一个 @Bean 要添加到应用程序 TargetingContextAccessor。 允许 TargetingContextAccessor 定义要用于定义当前用户 ID 和组的当前 TargetingContext 用户 ID 和组,如以下示例所示:

public class MyTargetingContextAccessor implements TargetingContextAccessor {

    @Override
    public void getContextAsync(TargetingContext context) {
        context.setUserId("Jeff");
        ArrayList<String> groups = new ArrayList<String>();
        groups.add("Ring0");
        context.setGroups(groups);
    }

}

目标评估选项

选项可用于自定义如何在给定 TargetingFilter范围内执行目标评估。 可以在创建过程中TargetingFilter设置可选参数TargetingEvaluationOptions

    @Bean
    public TargetingFilter targetingFilter(MyTargetingContextAccessor contextAccessor) {
        return new TargetingFilter(contextAccessor, new TargetingEvaluationOptions().setIgnoreCase(true));
    }

配置刷新

为配置启用配置刷新后,可以从应用程序配置存储或存储中拉取其最新值,而无需重启应用程序。

若要启用刷新,需要启用监视以及监视触发器。 监视触发器是一个键,其中包含一个可选标签,该标签检查值更改以触发更新。 只要需要刷新,监视触发器的值就可以是任何值。

注意

更改监视触发器 ETag 的任何操作都会导致刷新,例如内容类型更改。

spring:
  cloud:
    azure:
      appconfiguration:
        stores:
        - monitoring:
          enabled: true
          triggers:
          - key: [my-watched-key]
            label: [my-watched-label]

若要触发配置刷新,请在配置存储中更改密钥的值。 然后,将其中一个监视键更新为新值。 此更改触发日志的创建。 例如,更改以下日志消息的 /application/config.message 触发器值:

INFO 17496 --- [TaskScheduler-1] o.s.c.e.event.RefreshEventListener       : Refresh keys changed: [config.message]

应用程序生成日志后,它会刷新 @Bean刷新范围中的所有日志。

注意

默认情况下, @ConfigurationProperties 带批注的豆类包含在此范围内。

基于拉取的刷新

应用程序配置 Spring 库支持定期检查对监视触发器所做的更改的刷新间隔。 默认情况下,刷新间隔设置为 30 秒。 刷新间隔过后,所有触发器都会在给定存储中检查更改。 对密钥所做的任何更改都会导致刷新触发。 由于库与 Spring refresh 系统集成,因此任何刷新都会重新加载所有存储中的所有配置。 可以将刷新间隔设置为超过 1 秒的任何间隔。 刷新间隔支持单位分别为smhd、分钟、小时和天。 以下示例将刷新间隔设置为 5 分钟:

spring.cloud.azure.appconfiguration.stores[0].monitoring.refresh-interval= 5m

自动化

使用spring-cloud-azure-appconfiguration-config-web库时,应用程序会在发生 servlet 请求时自动检查刷新,具体而言ServletRequestHandledEvent。 此事件发送的最常用方式是向终结点 @RestController发出的请求。

手动

在仅 spring-cloud-azure-appconfiguration-config使用的应用程序(例如控制台应用程序)中,可以通过调用 AppConfigurationRefresh的方法 refreshConfiguration 手动触发刷新。 AppConfigurationRefresh 是一个 @Bean 你可以注入到任何 @Component

此外,由于库使用 Spring 的配置系统,因此触发刷新会导致刷新所有配置,而不仅仅是从Azure 应用程序配置存储中重新加载这些配置。

基于推送的刷新

你可以设置spring-cloud-azure-appconfiguration-config-web库以接收来自Azure 应用程序配置存储的推送通知以刷新配置值。 可以通过 Azure 事件网格 WebHook 设置此配置,该挂钩可配置为向指定密钥发送更改通知。 通过将 Spring 执行器库添加为依赖项,可以公开应用程序配置的刷新终结点。 有两个不同的终结点: appconfiguration-refreshappconfiguration-refresh-bus。 这些终结点的工作方式与其对应refreshrefresh-bus终结点类似,应用配置终结点在刷新间隔过期,而不是在接收时强制刷新。 你仍然可以使用refreshrefresh-bus,但不能直接将它们连接到使用 WebHook Azure 事件网格,因为它们需要设置中的响应。

appconfiguration-refresh属性将过期刷新间隔,因此,在下一次刷新检查之前,不会等待剩余的刷新间隔。 该appconfiguration-refresh-bus属性将通知发送到连接的消息传递服务(例如Azure 服务总线),以通知应用程序的所有实例进行刷新。 在这两种情况下,它不会在刷新间隔完全过期,但会以较小的抖动量关闭。 此抖动可确保应用程序的每个实例不会同时尝试刷新。

management.endpoints.web.exposure.include= appconfiguration-refresh, appconfiguration-refresh-bus

除了公开刷新终结点之外,还添加了所需的查询参数以确保安全性。 默认情况下未设置令牌名称或值,但设置一个是使用终结点所必需的,如以下示例所示:

spring.cloud.azure.appconfiguration.stores[0].monitoring.push-notification.primary-token.name=[primary-token-name]
spring.cloud.azure.appconfiguration.stores[0].monitoring.push-notification.primary-token.secret=[primary-token-secret]
spring.cloud.azure.appconfiguration.stores[0].monitoring.push-notification.secondary-token.name=[secondary-token-name]
spring.cloud.azure.appconfiguration.stores[0].monitoring.push-notification.secondary-token.secret=[secondary-token-secret]

设置 Web 挂钩

若要设置 Web 挂钩,请打开Azure 应用程序配置存储和从导航菜单中打开“事件”。 然后选择“ 事件订阅”。 设置事件的名称,并选择终结点类型为 WebHook。 选择 Web 挂钩会导致 显示终结点 选项。 选择“选择终结点”。 终结点应如以下示例所示: https://www.myaplication.com/actuator/appconfiguration-refresh?myTokenName=mySecret

确认选择 将设置通知发送到给定的 URI,并且需要响应。 如果未返回响应,安装程序将失败。 azure-spring-cloud-appconfiguration-web如果为应用程序配置了Azure 应用程序配置存储,终结点的库设置将返回正确的响应。 可以通过其他方式发送此确认。 有关 Web 挂钩传递的详细信息,请参阅 Webhook 事件传递

注意

此验证仅在创建或修改终结点时发生。

强烈建议设置筛选器,因为否则,每次创建和修改密钥后都会触发刷新。

强制客户端刷新

可以将库配置为按刷新间隔强制刷新所有配置。 下表描述了该 refresh-interval 属性:

名称 说明 需要 默认
spring.cloud.azure.appconfiguration.refresh-interval 刷新之间的标准时间量。 是一个 Duration Null

刷新spring.cloud.azure.appconfiguration.refresh-interval时不会检查任何配置的监视密钥。 此属性用于确保密钥库机密保持最新状态,因为Azure 应用程序配置无法判断它们何时更新。

由于 Azure 密钥库将证书的公钥和私钥对存储为机密,因此应用程序可以将任何证书作为应用程序配置中的密钥库引用检索。 由于需要定期轮换证书,客户端应用程序需要像频繁一样频繁地更新,这可以通过使用客户端刷新间隔来完成。

功能标志刷新

如果同时启用功能标志和监视,则默认情况下,功能标志的刷新间隔设置为 30 秒。 刷新间隔过后,所有功能标志都会在给定存储中检查更改。 对密钥所做的任何更改都会导致刷新触发。 由于库与 Spring refresh 系统集成,因此任何刷新都会重新加载所有存储中的所有配置。 可以将刷新间隔设置为超过 1 秒的任何间隔。 刷新间隔支持单位分别为smhd、分钟、小时和天。 以下示例将刷新间隔设置为 5 分钟:

spring.cloud.azure.appconfiguration.stores[0].monitoring.feature-flag-refresh-interval= 5m

运行状况指示器

客户端库附带一个运行状况指示器,该指示器检查与Azure 应用程序配置存储或存储的连接是否正常。 如果为每个存储区启用,则会提供以下状态值之一:

  • UP - 上次连接成功。
  • DOWN - 最后一个连接导致非 200 错误代码。 此状态可能是由于凭据过期到服务问题等问题造成的。 客户端库会在下次刷新间隔自动重试以连接到存储区。
  • NOT LOADED - 配置存储列在本地配置文件中,但在启动时未从文件加载配置存储。 配置文件中禁用配置存储,或者当存储的配置设置为 falsefail-fast,配置或配置在启动时无法加载。

可以通过设置 management.health.azure-app-configuration.enabled=true启用运行状况指示器。

客户端自定义

应用程序配置库使用用于 JavaAzure SDK 连接到 Azure 应用程序配置 和 Azure 密钥库。 提供了两个接口, ConfigurationClientCustomizer 并提供 SecretClientCustomizer两个接口来修改客户端。 每个接口都有一个 customize 方法,该方法采用各自的生成器以及 String 要为其配置客户端的 URI 的值,如以下接口定义所示:

public interface ConfigurationClientCustomizer {
    public void setup(ConfigurationClientBuilder builder, String endpoint);
}

public interface SecretClientCustomizer {
    public void setup(SecretClientBuilder builder, String endpoint);
}

这些接口允许自定义 HTTP 客户端及其配置。 以下示例将默认值HttpClient替换为另一个默认值,该代理将代理用于定向到应用程序配置和密钥库的所有流量。

注意

ConfigurationClientBuilderSecretClientBuilder已设置为在传入customize时使用。 对客户端所做的任何更改(包括凭据和重试策略)都会替代已就位的更改。

还可以使用 Spring Cloud Azure 配置执行此配置

public class CustomClient implements ConfigurationClientCustomizer, SecretClientCustomizer {

    @Override
    public void customize(ConfigurationClientBuilder builder, String endpoint) {
        builder.httpClient(buildHttpClient());
    }

    @Override
    public void customize(SecretClientBuilder builder, String endpoint) {
        builder.httpClient(buildHttpClient());
    }

    private HttpClient buildHttpClient() {
        String hostname = System.getProperty("https.proxyHosts");
        String portString = System.getProperty("https.proxyPort");
        int port = Integer.valueOf(portString);

        ProxyOptions proxyOptions = new ProxyOptions(ProxyOptions.Type.HTTP,
                new InetSocketAddress(hostname, port));
        return new NettyAsyncHttpClientBuilder()
                .proxy(proxyOptions)
                .build();
    }

}