{"id":15294763,"url":"https://github.com/code2life/spring-boot-dynamic-config","last_synced_at":"2025-04-09T12:06:58.965Z","repository":{"id":41556007,"uuid":"371276921","full_name":"Code2Life/spring-boot-dynamic-config","owner":"Code2Life","description":"Dynamic Configuration Capability for SpringBoot Application","archived":false,"fork":false,"pushed_at":"2023-05-24T12:03:32.000Z","size":512,"stargazers_count":236,"open_issues_count":3,"forks_count":42,"subscribers_count":11,"default_branch":"main","last_synced_at":"2025-04-02T10:12:30.962Z","etag":null,"topics":["configuration","dynamic","file-watcher","nacos","springboot"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Code2Life.png","metadata":{"files":{"readme":"README-zh.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-05-27T06:59:13.000Z","updated_at":"2025-02-26T04:09:29.000Z","dependencies_parsed_at":"2024-12-24T18:10:41.370Z","dependency_job_id":"d822d659-7ad1-40c1-91b6-438f15860d1d","html_url":"https://github.com/Code2Life/spring-boot-dynamic-config","commit_stats":{"total_commits":49,"total_committers":4,"mean_commits":12.25,"dds":0.4693877551020408,"last_synced_commit":"b25e03f76ab93329c707ad80e6d0a257d3a8dbf3"},"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Code2Life%2Fspring-boot-dynamic-config","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Code2Life%2Fspring-boot-dynamic-config/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Code2Life%2Fspring-boot-dynamic-config/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Code2Life%2Fspring-boot-dynamic-config/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Code2Life","download_url":"https://codeload.github.com/Code2Life/spring-boot-dynamic-config/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248036063,"owners_count":21037092,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["configuration","dynamic","file-watcher","nacos","springboot"],"created_at":"2024-09-30T17:06:47.698Z","updated_at":"2025-04-09T12:06:58.939Z","avatar_url":"https://github.com/Code2Life.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"## Spring Boot Dynamic Config\n\n\u003cp align=\"left\"\u003e\n\u003cbr\u003e\n\u003ca href=\"https://github.com/code2life/spring-boot-dynamic-config\"\u003e\u003cimg src=\"https://github.com/code2life/spring-boot-dynamic-config/actions/workflows/gradle.yml/badge.svg\" /\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/code2life/spring-boot-dynamic-config/actions/workflows/gradle.yml\"\u003e\u003cimg src=\"https://filecdn.code2life.top/jacoco-sp.svg\" /\u003e\u003c/a\u003e\n\u003ca href=\"https://codebeat.co/projects/github-com-code2life-spring-boot-dynamic-config-main\"\u003e\u003cimg alt=\"codebeat badge\" src=\"https://codebeat.co/badges/ea7b2127-62f3-45f4-9f38-55f8203c0121\" /\u003e\u003c/a\u003e\n\u003cbr\u003e\n\u003c/p\u003e\n\n一个注解实现SpringBoot应用的**动态配置**，配置热重载最简洁的方案。\n\n[English](https://github.com/Code2Life/spring-boot-dynamic-config/blob/main/README.md) [简体中文](https://github.com/Code2Life/spring-boot-dynamic-config/blob/main/README-zh.md)\n\n- :heart: **无侵入**，完全兼容SpringBoot原生的配置获取方式（@Value / @ConfigurationProperties）\n- :zap: **超轻量，超快响应**, 不依赖SpringBoot核心库以外的任何三方库\n- :grinning: **极易使用**, 只提供一个简单的注解: @DynamicConfig；一个事件：ConfigurationChangedEvent\n- ☸ 在K8S集群中和K8S ConfigMap完美结合的SpringBoot/SpringCloud应用的动态配置方式\n\n#### 相比于spring-cloud-starter-config：\n\n- 不需要SpringCloud ConfigServer配置中心服务\n- 不需要SpringCloud依赖，不需要@RefreshScope注解，不会重建Spring Bean\n\n#### 相比于阿里Nacos/携程Apollo：\n\n- 不需要配置中心服务器\n- 不需要学习额外的注解和SDK API\n\n## 演示\n\n\u003cimg src=\"https://filecdn.code2life.top/springboot-config-demo.gif\" alt=\"Demo\" /\u003e\n\n## 快速开始\n\n### 步骤一：添加依赖spring-boot-dynamic-config\n\n注意：Spring Boot 2.4以下版本请使用 1.0.8 版本\n\nMaven\n\n```xml\n\n\u003cdependency\u003e\n    \u003cgroupId\u003etop.code2life\u003c/groupId\u003e\n   \u003cartifactId\u003espring-boot-dynamic-config\u003c/artifactId\u003e\n   \u003cversion\u003e1.0.9\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nGradle\n\n```groovy\nimplementation 'top.code2life:spring-boot-dynamic-config:1.0.9'\n```\n\n### 步骤二：在代码中添加 @DynamicConfig 注解\n\n**使用方法1: 在包含@Value成员的类上添加 @DynamicConfig。**\n\n```java\nimport lombok.Data;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.stereotype.Component;\nimport top.code2life.config.DynamicConfig;\n\nimport java.util.Set;\n\n@Data\n@Component\n@DynamicConfig // add annotation here !\npublic class DynamicFeatures {\n\n    @Value(\"${dynamic-test-plain:default}\")\n    private String plainValue;\n\n    @Value(\"#{@featureGate.convert('${dynamic-feature-conf}')}\")\n    private Set\u003cString\u003e someBetaFeatureConfig;\n\n    // @DynamicConfig // adding annotation here also works!\n    @Value(\"#{@testComponent.transform(${dynamic.transform-a:20}, ${dynamic.transform-b:10})} \")\n    private double transformBySpEL;\n\n\n    public double transform(double t1, double t2) {\n        return t1 / t2;\n    }\n}\n\n// file: application-profile.yml\n// ============================\n// dynamic-test-plain: someVal # kebab-case is recommended\n// dynamicFeatureConf: a,b,c  # camelCase compatible\n// dynamic:\n//   transform-a: 100\n//   transform-b: 10\n```\n\n**使用方法2: 在有 @ConfigurationProperties 注解的类上添加 @DynamicConfig。**\n\n```java\nimport lombok.Data;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.context.annotation.Configuration;\nimport top.code2life.config.DynamicConfig;\n\nimport java.util.Map;\n\n@Data\n@DynamicConfig  // add annotation here !\n@Configuration\n@ConfigurationProperties(prefix = \"my-prop\")\npublic class TestConfigurationProperties {\n\n    private String str;\n\n    private Double doubleVal;\n\n    private Map\u003cString, Object\u003e mapVal;\n}\n\n// file: application-another-profile.yml\n// ============================\n// my-prop:  # or myProp, relax binding supported \n//   str: someVal\n//   double-val: 100.0\n//   mapVal:\n//     k: v\n```\n\n### 步骤三：使用指定配置路径的方式启动SpringBoot应用\n\n```bash\njava -jar your-spring-boot-app.jar --spring.config.location=/path/to/config\n```\n\n在Dynamic Config的1.0.9版本支持了Spring Boot 2.4之后版本的 'spring.config.import' 特性，并且增强了原生的 configtree 特性！\n\n```bash\n# config.import could be used with config.location TOGETHER\njava -jar your-spring-boot-app.jar --spring.config.import=/path/to/configA.yaml,/path/to/configB.yaml\n# or use the config tree feature\njava -jar your-spring-boot-app.jar --spring.config.import=configtree:/path/to/conf-dir/\n```\n\n启动后配置路径下的**任何文件修改**（/path/to/config/application-xxx.yml）都会在**相关联的注有@DynamicConfig的Spring Bean里立即生效**\n，getter方法可以直接获取到最新配置值。\n\n### 新特性：Import Config Tree\n\nSpring Boot 2.4之后支持了导入配置文件或目录的参数，比如'--spring.config.import=configtree:/path/to/conf-dir/' 这个启动参数会让Spring\nBoot递归查找所有子目录和文件，加载到Spring Environment中作为Property，Key就是文件相对路径名：\n\n比如配置文件是： 'path/to/conf-dir/module-a/file-b.yaml', 则代码中可以用 'module-a.file-b.yaml'\n取到文件的内容，但类型只有String，并没有加载成完整的PropertySource。\n\nDynamic Config 1.0.9 版本增强了这个特性，如果查找到带后缀的配置文件，会额外加载到Spring Environment中成为独立的、可热重载的PropertySource，使用方式如下。\n\n举个例子，比如spring.config.import目录是 '/path/to/conf-dir', 子目录中有这个配置文件 '/path/to/conf-dir/module-a/file-b.yaml'\n\n```yaml\n# file: /path/to/conf-dir/module-a/file-b.yaml\nprop-c-in-file: example-value\n\nprop-obj-key-infile:\n  fieldA: value\n  fieldB: value\n```\n\n代码中无需做任何变更，只需要加上文件路径的前缀即可，比如 module-a/file-b.yaml =\u003e module-a.file-b。\n\n```java\n@Value(\"${module-a.file-b.prop-c-in-file}\")\n@DynamicConfig\nprivate String loadedByConfigTree\n\n// or\n@DynamicConfig\n@ConfigurationProperties(prefix = \"module-a.file-b.prop-obj-key-infile\")\npublic class PropsLoadedByConfigTree {\n  // ...\n}\n```\n\n参考文档: https://docs.spring.io/spring-boot/docs/2.7.3/reference/htmlsingle/#features.external-config.files.configtree\n\n### 配置管理的最佳实践\n\n- 以代码的方式管理配置，Everything as Code；\n- Git是维护配置信息的最佳版本控制系统，绝大多数应用，不需要配置管理中心这样的系统；\n- 配置由**持续集成系统自动化部署**到开发/产线环境，而不是登陆到某个系统，手动输入配置值；\n- Git Ops的方式做自动化运维，更符合DevOps的思想，在应用服务数量非常多的时候，也更具备伸缩性。\n\n## 实现核心逻辑\n\n1. 使用 --spring.config.location 参数启动时，初始化 DynamicConfigPropertiesWatcher 这个Bean；\n2. 与此同时，初始化 DynamicConfigBeanPostProcessor 这个BeanPostProcessor，用来处理 @DynamicConfig；\n3. DynamicConfigBeanPostProcessor 收集所有带有 @DynamicConfig 注解的Bean的元数据，包括Bean的名称、实例、@Value成员变量等等；\n4. DynamicConfigPropertiesWatcher 开始监听 spring.config.location\n   目录下所有的文件变动，对于变化的Yaml/Properties，生成PropertySource动态替换Environment Bean中的PropertySource；\n5. DynamicConfigPropertiesWatcher 在ApplicationContext中发布配置变动的Event：ConfigurationChangedEvent；\n6. DynamicConfigBeanPostProcessor 订阅了上述事件，计算变动的文件，对哪些Key造成了差异\n7. 对于每个有差异的Property Key, DynamicConfigBeanPostProcessor 比对记录的Bean元数据，找到相关联的Bean\n8. 对于这次变动相关联的Bean, 调用反射方法，或 ConfigurationPropertiesBindingPostProcessor 的API，绑定到当前Bean的成员变量中，实现配置动态生效\n\n## 兼容性\n\n任何SpringBoot/SpringCloud应用都可以使用这个库，只要依赖的SpringBoot版本在SpringBoot 2.0以上即可。\n\n- √ SpringBoot 2.4.x, 2.5.x, 2.6.x, 2.7.x, 3.0.0 and Above (1.0.9以上版本)\n- √ SpringBoot 2.3.x (1.0.8及以下版本)\n- √ SpringBoot 2.2.x (1.0.8及以下版本)\n- √ SpringBoot 2.1.x (1.0.8及以下版本)\n- √ SpringBoot 2.0.x (1.0.8及以下版本)\n- X SpringBoot 1.5.x 不支持\n\n注意:\n\n- SpringBoot 2.0.x中不能使用JUnit5，只能使用JUnit4，因此在Spring 2.0.x版本跑本仓库里的单元测试，需要切换到JUnit4\n- spring-boot-dynamic-config仅包含spring-boot库的编译依赖，不依赖任何其他三方库\n\n## 开源许可证\n\nSpring Boot Dynamic Config is Open Source software released under\nthe [Apache 2.0 license](https://www.apache.org/licenses/LICENSE-2.0.html).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcode2life%2Fspring-boot-dynamic-config","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcode2life%2Fspring-boot-dynamic-config","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcode2life%2Fspring-boot-dynamic-config/lists"}