💪💪永久更新承诺
我们郑重承诺,所有订阅合集的粉丝都将享受永久免费的后续更新服务。
💌💌如何获取
订阅我们的合集《点我订阅》,并通过私信联系我们,我们将第一时间将电子书发送给您。
环境:SpringBoot3.4.2
1. 简介
在项目开发里,由于不同业务场景的需求多变,新功能上线可能存在风险,且不同用户群体对功能需求有差异。功能开关能灵活控制功能启用与关闭,便于快速迭代、降低风险,还能实现功能的个性化投放,满足多样化业务需求。
在Spring Boot中,功能开关可通过@Profile按环境激活、@ConditionalOnProperty按属性配置控制等条件注解、@RefreshScope实现动态刷新配置。对于条件注解的更多内容请查看下面链接:
而在本篇文章中我们将介绍一个非常不错的开源功能开关组件:OpenFeature。
什么是OpenFeature?
OpenFeature 提供了一个共享的、标准化的特性标志客户端——即一个软件开发工具包(SDK),该工具包可接入各种第三方特性标志提供商。无论你使用的是开源系统还是商业产品,无论它是自行托管还是云托管,OpenFeature 都为开发人员提供了一个一致、统一的 API,以便他们在应用程序中使用特性标志功能。
此图展现了,OpenFeature与"Flags-R-us"旗帜管理系统集成。
为实现这一目标,OpenFeature SDK 定义了若干灵活的抽象层
Evaluation API
Evaluation API是OpenFeature软件开发工具包(SDK)中与应用程序编写者交互的部分。它允许开发人员评估特性标志,并利用所得结果来影响控制流程或应用程序特性。评估API提供了一个框架,允许对行为进行定制,并与各种工具集成。
Evaluation Context
Evaluation Context是一个用于存储任意上下文数据的容器,这些数据可作为动态评估的基础。诸如主机或应用程序标识符等静态数据可进行全局配置。动态评估上下文(如Web应用程序中客户端的IP地址)可在标志评估期间隐式传播或显式传递,并且可以与静态值合并。
Providers
Provider是Evaluation API与所使用的标志管理系统之间的“转换层”。提供程序负责将提供给评估API的参数映射到关联标志管理系统中的等效表示形式。提供程序可能会封装供应商软件开发工具包(SDK)、调用定制的标志评估REST API,甚至解析某些本地存储的文件以解析标志值。
Hooks
钩子是一种机制,允许在标志评估生命周期的各个点添加任意行为。钩子让你能够扩展OpenFeature SDK,添加诸如验证已解析标志值、修改或向评估上下文添加数据、日志记录、遥测和跟踪等功能。
Events
事件使应用程序能够对提供程序或底层标志管理系统的状态变化做出反应。这些变化包括提供程序就绪状态、错误状态的变化,或者最有趣的是,标志配置的变化。
接下来,我们将基于Spring Boot详细的介绍OpenFeature的使用。
<dependency><groupId>dev.openfeature</groupId><artifactId>sdk</artifactId><version>1.15.1</version></dependency><dependency><groupId>dev.openfeature.contrib.providers</groupId><artifactId>flagd</artifactId><version>0.11.10</version></dependency>
OpenFeatureAPI 类是访问OpenFeature SDK的主要入口点。该类被设计为单例模式。如下示例:
@Configurationpublic class OpenFeatureConfig {@BeanOpenFeatureAPI openFeatureAPI() {final OpenFeatureAPI openFeatureAPI = OpenFeatureAPI.getInstance();return openFeatureAPI;}}
public class FeatureController {private final OpenFeatureAPI openFeatureAPI ;public FeatureController(OpenFeatureAPI openFeatureAPI) {this.openFeatureAPI = openFeatureAPI;}public String getHello() {final Client client = openFeatureAPI.getClient();// 判断功能标记 welcome-message 的状态if (client.getBooleanValue("welcome-message", false)) {return "您好,欢迎使用OpenFeature!";}return "Hello!";}}
提供程序是 OpenFeature 中的重要概念,因为它们负责实际执行标志评估。正如上一步所示,未配置提供程序的 OpenFeature 始终返回默认值。若要实现真正的功能标志控制,我们需要注册一个提供程序。
如下示例,我们配置了一个基于内存的Provider:
OpenFeatureAPI openFeatureAPI() {final OpenFeatureAPI openFeatureAPI = OpenFeatureAPI.getInstance();Map<String, Flag<?>> flags = Map.of("welcome-message", Flag.builder().variant("on", true).variant("off", false).defaultVariant("on").build()) ;openFeatureAPI.setProvider(new InMemoryProvider(flags )) ;return openFeatureAPI;}
OpenFeatureAPI openFeatureAPI() {final OpenFeatureAPI openFeatureAPI = OpenFeatureAPI.getInstance();ContextEvaluator<Object> context = new ContextEvaluator<Object>() {public Object evaluate(Flag flag, EvaluationContext evaluationContext) {Value value = evaluationContext.getValue("region") ;String region = flag.getFlagMetadata().getString("region") ;return region.equals(value.asString()) ;}} ;Map<String, Flag<?>> flags = Map.of("welcome-message", Flag.builder().flagMetadata(ImmutableMetadata.builder().addString("region", "xj").build()).contextEvaluator(context).build()) ;openFeatureAPI.setProvider(new InMemoryProvider(flags)) ;return openFeatureAPI;}
("/hello")public String getHello(String region) {final Client client = openFeatureAPI.getClient();EvaluationContext context = new MutableContext(Map.of("region", new Value(region)));if (client.getBooleanValue("welcome-message", false, context)) {return "您好,欢迎使用OpenFeature!";}return "Hello!";}
flagd 是一款秉承 Unix 哲学的特性开关守护进程。可将其视为现成的、开源的、符合 OpenFeature 规范的特性开关后端系统。
https://github.com/open-feature/flagd/releases
./flagd start --port 8013 --uri file:./app.flagd.json
# 下载镜像docker pull ghcr.io/open-feature/flagd:latest# 启动服务docker run -p 8013:8013 -v $(pwd)/:/etc/flagd/-it ghcr.io/open-feature/flagd:latest start--uri file:/etc/flagd/app.flagd.json
{"flags": {"welcome-message": {"variants": {"on": true,"off": false},"state": "ENABLED","defaultVariant": "on"}}}
OpenFeatureAPI openFeatureAPI() {final OpenFeatureAPI openFeatureAPI = OpenFeatureAPI.getInstance();openFeatureAPI.setProviderAndWait(new FlagdProvider()) ;return openFeatureAPI;}
filepath event: ./app.flagd.json WRITE {"component": "sync", "sync": "fileinfo"}
只会用map()和filter()?揭秘Java Stream 8大隐藏特性
自定义@Proxy注解!Spring Boot 动态控制代理功能,真的很强大
高级开发!Spring Boot 事务钩子终极方案:一个注解搞定
强大!Spring Boot 动态JSON字段按需输出,一个注解搞定
优雅!Spring Boot 一个注解,开启 SQL 数据动态权限控制
开发效率提升300%:Spring Boot + Temporal 用代码定义工作流
Spring Boot + JasperReport 一键生成PDF、HTML 与 XML 报表
Spring Boot 通过@JsonComponent注解完全控制JSON数据
高级开发!Spring Boot 手写配置类动态刷新,多知识点综合应用

