跳到内容

Feature Flag Starter

受众:开发者 摘要:Pennant-like 功能开关底座。支持配置式开关、数据库动态 Store、属性 gate、确定性百分比 rollout、variant、Facade 调用和 Admin 管理。

何时使用

场景建议
新功能分批开放配置 rollout-percentage,按用户或租户稳定分桶
付费 / 套餐能力可见性使用 attributes 限定 plantenantregion 等上下文
A/B 试验轻量分流配置 variants 权重,业务读取当前 variant
单元测试 / 隔离诊断中临时关闭能力使用 spring.open.feature-flag.flags.<name>.enabled=false
需要后台审计和动态变更使用 spring-open-core-feature-flag,通过 Admin 功能开关页面维护数据库定义并刷新运行时 Store

Feature Flag 是运行时能力开关,不替代 IAM 权限、套餐余额、风控规则或配置中心。权限判断仍走 IAM / Entitlement;开关只决定“当前代码路径是否启用”。轻量项目可以只使用 starter 的配置文件 Store;默认应用装配会引入 spring-open-core-feature-flag,数据库 Store 优先、配置文件 Store 兜底。

快速开始

xml
<dependency>
    <groupId>com.springopen</groupId>
    <artifactId>spring-open-starter-feature-flag</artifactId>
</dependency>
yaml
spring:
  open:
    feature-flag:
      enabled: true
      default-enabled: false
      flags:
        new-checkout:
          enabled: true
          rollout-percentage: 25
          attributes:
            plan: pro
          variants:
            blue: 70
            green: 30
java
FeatureFlagContext context = FeatureFlagContext.user(userId)
        .withAttribute("plan", "pro");

if (FeatureFlags.enabled("new-checkout", context)) {
    Optional<String> variant = FeatureFlags.variant("new-checkout", context);
    // run new checkout
}

机制说明

层级职责
FeatureFlags静态 Facade,业务代码最常用入口
FeatureFlagManager合并默认值、属性 gate、rollout 和 variant
FeatureFlagStore开关定义来源 SPI
PropertiesFeatureFlagStore默认配置文件 store,不依赖数据库
FeatureFlagContext调用方传入 actor 和属性,starter 不绑定 IAM / Tenant

评估顺序:

  1. 按名称读取 FeatureFlagStore
  2. 未声明时返回 default-enabled
  3. 已声明时先解析 enabled,为空则继承 default-enabled
  4. attributes 全部精确匹配后才进入 rollout。
  5. rollout-percentage 通过 flagName + actorType + actorId 做 SHA-256 稳定分桶。
  6. 开启后按 variants 权重返回稳定 variant。

百分比 rollout 是确定性的:同一个 flag + actor 会长期命中同一个 bucket,适合灰度发布和回滚。匿名上下文使用 anonymous:anonymous,只适合全局开关或本地 smoke;用户、租户、应用等真实灰度应传入明确 actor。

配置项

yaml
spring:
  open:
    feature-flag:
      enabled: true
      default-enabled: false
      flags:
        feature-name:
          enabled: true
          description: New checkout flow
          rollout-percentage: 100
          attributes:
            plan: pro
          variants:
            a: 50
            b: 50
配置默认值说明
enabledtrue是否启用 starter 自动装配
default-enabledfalse未声明开关或开关未显式配置 enabled 时的默认状态
flags.<name>.enabled显式开关状态;为空时继承 default-enabled
flags.<name>.description面向文档、后台和排障的人类可读描述
flags.<name>.rollout-percentage100开启后的百分比灰度,范围自动收敛到 0..100
flags.<name>.attributes必须匹配的上下文属性键值
flags.<name>.variantsvariant 权重,非正数权重会被忽略

扩展 Store

业务项目可以提供自定义 FeatureFlagStore Bean,自动配置会让出默认配置文件 store。默认应用已提供数据库 Store:

java
@Bean
FeatureFlagStore databaseFeatureFlagStore(...) {
    return new DatabaseFeatureFlagStore(...);
}

自定义 store 只负责返回 FeatureFlagDefinition,不要把灰度算法和 Facade 状态复制到业务模块。需要后台管理、缓存刷新、权限菜单和数据库持久化时,优先使用 spring-open-core-feature-flag 管理面消费这个 SPI。

管理控制台

spring-open-core-feature-flag 提供后台管理 API 和 Admin 页面:

能力说明
数据表feature_flag 存储开关编码、名称、描述、启停、灰度百分比、属性 gate、variant 权重、排序和系统托管标记
后台 API/api/v1/admin/feature-flags/** 提供分页、详情、新增、更新、启停、批量删除、评估和刷新 Store
权限feature-flag:flag:view/create/update/delete
菜单Admin 内置 功能开关 / Feature Flags,默认归入系统管理域
StoreDatabaseFeatureFlagStore 优先读取数据库定义;数据库不存在定义时回退 starter 配置文件定义
多节点刷新默认本机刷新;启用 spring.open.feature-flag.cluster.enabled=true 且存在 Redisson 时,通过 Redis Topic 广播刷新事件

Admin 页面支持搜索、启停、灰度百分比、属性 JSON、variant JSON、手动评估和刷新 Store。属性 JSON 值按字符串精确匹配;variant JSON 值为权重数字。

多节点刷新

单机或 lite 场景下,后台保存功能开关后只刷新当前进程内的 DatabaseFeatureFlagStore 缓存。多实例部署如果需要节点间即时同步,可以开启 core 模块的 Redis Topic 刷新广播:

yaml
spring:
  open:
    feature-flag:
      cluster:
        enabled: true
        topic: feature-flag.refresh
        node-id: admin-node-1

开启后,当前节点保存、启停、删除或手动刷新功能开关时会先刷新本机缓存,再向 Redis Topic 发布刷新消息;其他节点收到消息后只刷新本机缓存,不再二次广播,避免循环 fan-out。node-id 留空时会自动生成,生产多副本建议配置为稳定实例标识,便于排障。

审计

后台创建、更新、启停和删除 Feature Flag 时,会额外写入 Audit 操作日志短摘要。更新摘要只记录字段级差异,例如名称、启停状态、灰度比例、attributes、variants 和排序变化;JSON 字段只写入截断后的变化摘要,避免把大段配置塞入操作日志。审计失败不会阻断 Feature Flag 保存或刷新。

验证

bash
./mvnw -pl spring-open-starters/spring-open-starter-feature-flag -am test -DskipITs -DskipFrontend -Dsurefire.failIfNoSpecifiedTests=false
./mvnw -pl spring-open-core/spring-open-core-feature-flag,spring-open-application -am test -DskipITs -DskipFrontend -Dsurefire.failIfNoSpecifiedTests=false
pnpm -C views/admin typecheck
git diff --check -- spring-open-starters/spring-open-starter-feature-flag spring-open-core/spring-open-core-feature-flag views/admin/src/views/feature-flag views/admin/src/api/feature-flag.ts docs/zh-CN/feature-flag.md

Released under the Apache License 2.0.