手撸一个SpringBoot配置中心实现配置动态刷新
业务需求
SpringBoot项目配置信息大多使用@Value注解或者@ConfigurationProperties注解读取配置信息,线上项目经常需要对某些配置进行调整,如果每次都需要修改配置文件再重新发布服务,难免会导致服务中断。
尤其是在分布式系统中多个服务节点都需要修改配置文件的场景,基于此配置中心也应运而生。
如果我们的项目使用了SpringCloud,那么可选的配置中心有很多,比如Nacos、spring-cloud-starter-config、Apollo等,这些配置中心都需要借助SpringCloud架构才能实现配置刷新。
这里我们的应用没有集成SpringCloud,也不想因为配置中心而让应用架构变重,所以需要基于SpringBoot基础实现一个轻量级的配置动态刷新功能。
远程配置中心
对配置资源进行管理,所有应用连接配置中心读取配置信息,可选用的配置中心包括:
1、配置中心中间件,例如:Nacos;
2、数据库存储;
3、Git仓库;
4、文件系统;
5、其它具备持久化存储及访问功能的中间件。
说点听得懂的实现原理
想要实现配置动态刷新可以从Spring的Bean初始化和属性值注入原理入手,这里我们跳过原理分析阶段,感兴趣的同学自行百度,建议大家可以直接看下Spring的PropertyPlaceholderAutoConfiguration类。
刷新配置信息仅需简单两步:
1、刷新Spring的Environment环境变量;
2、刷新Spring托管的Bean实例的属性值;
刷新Environment
/**
* 刷新环境变量
* @param properties
*/
private MutablePropertySources refreshEnvironment(Properties properties) {
Map<String, Object> props = new HashMap<>();
properties.stringPropertyNames().stream().forEach(key ->
props.put(key, properties.getProperty(key))
);
// 获取spring的environment
MutablePropertySources mutablePropertySources = environment.getPropertySources();
// 添加远程配置信息
mutablePropertySources.addFirst(new MapPropertySource("remoteConfig", props)); return mutablePropertySources;
}
刷新Bean实例
需要注意一下几点:
1、我们不用自己解析@Value的value,通过Spring提供的PropertySourcesPropertyResolver.resolveRequiredPlaceholders即可从环境变量中获取对应的属性值;
2、@Value可以使用EL表达式,注入的属性类型可以是String、List等对象,通过Spring提供的SpelExpressionParser类实现EL表达式解析和运算取值。
/**
* 刷新Bean实例的属性值
* @param bean
* @param propertyResolver
*/
private void refreshBean(Object bean, ConfigurablePropertyResolver propertyResolver) { // 定义EL表达式解释器
SpelExpressionParser spelExpressionParser;
spelExpressionParser = new SpelExpressionParser();
TemplateParserContext templateParserContext;
templateParserContext = new TemplateParserContext(); String keyResolver, valueResolver = null;
Object parserValue;
// 遍历Bean实例所有属性
for (Field field : bean.getClass().getDeclaredFields()) {
// 判断field是否含有@Value注解
if (field.isAnnotationPresent(Value.class)) {
// 读取Value注解占位符
keyResolver = field.getAnnotation(Value.class).value();
try {
// 读取属性值
valueResolver = propertyResolver.resolveRequiredPlaceholders(keyResolver);
// EL表达式解析
// 兼容形如:@Value("#{'${url}'.split(',')}")含有EL表达式的情况
parserValue = spelExpressionParser.parseExpression(valueResolver, templateParserContext).getValue(field.getType()); } catch (IllegalArgumentException e) {
log.warn("{}", e.getMessage());
continue;
}
// 判断配置项是否存在
if (Objects.nonNull(valueResolver)) {
field.setAccessible(true);
try {
field.set(bean, parserValue);
continue;
} catch (IllegalAccessException e) {
log.error("{}刷新属性值出错, bean: [{}], field: [{}], value: [{}]",
TAG, bean.getClass().getName(), field.getName(), valueResolver);
}
}
}
}
}

手撸一个SpringBoot配置中心实现配置动态刷新的更多相关文章
- 手撸一个SpringBoot的Starter,简单易上手
前言:今天介绍一SpringBoot的Starter,并手写一个自己的Starter,在SpringBoot项目中,有各种的Starter提供给开发者使用,Starter则提供各种API,这样使开发S ...
- 看了 Spring 官网脚手架真香,也撸一个 SpringBoot DDD 微服务的脚手架!
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 为什么我们要去造轮子? 造轮子的核心目的,是为了解决通用共性问题的凝练和复用. 虽然 ...
- 手撸一个SpringBoot-Starter
1. 简介 通过了解SpringBoot的原理后,我们可以手撸一个spring-boot-starter来加深理解. 1.1 什么是starter spring官网解释 starters是一组方便的依 ...
- 手撸一个springsecurity,了解一下security原理
手撸一个springsecurity,了解一下security原理 转载自:www.javaman.cn 手撸一个springsecurity,了解一下security原理 今天手撸一个简易版本的sp ...
- 【手撸一个ORM】MyOrm的使用说明
[手撸一个ORM]第一步.约定和实体描述 [手撸一个ORM]第二步.封装实体描述和实体属性描述 [手撸一个ORM]第三步.SQL语句构造器和SqlParameter封装 [手撸一个ORM]第四步.Ex ...
- C#基于Mongo的官方驱动手撸一个Super简易版MongoDB-ORM框架
C#基于Mongo的官方驱动手撸一个简易版MongoDB-ORM框架 如题,在GitHub上找了一圈想找一个MongoDB的的ORM框架,未偿所愿,就去翻了翻官网(https://docs.mongo ...
- 五分钟,手撸一个Spring容器!
大家好,我是老三,Spring是我们最常用的开源框架,经过多年发展,Spring已经发展成枝繁叶茂的大树,让我们难以窥其全貌. 这节,我们回归Spring的本质,五分钟手撸一个Spring容器,揭开S ...
- .Net Core 自定义配置源从配置中心读取配置
配置,几乎所有的应用程序都离不开它..Net Framework时代我们使用App.config.Web.config,到了.Net Core的时代我们使用appsettings.json,这些我们再 ...
- spring cloud 系列第8篇 —— config+bus 分布式配置中心与配置热刷新 (F版本)
源码Gitub地址:https://github.com/heibaiying/spring-samples-for-all 一.config 简介 spring cloud config 分为服务端 ...
- 通过 Netty、ZooKeeper 手撸一个 RPC 服务
说明 项目链接 微服务框架都包括什么? 如何实现 RPC 远程调用? 开源 RPC 框架 限定语言 跨语言 RPC 框架 本地 Docker 搭建 ZooKeeper 下载镜像 启动容器 查看容器日志 ...
随机推荐
- 轻松玩转70亿参数大模型!借助Walrus在AWS上部署Llama2
Llama 2 是 Meta 的下一代开源大语言模型.它是一系列经过预训练和微调的模型,参数范围从 70 亿到 700 亿个.Meta Llama 2 可免费用于研究和商业用途并且提供了一系列具有不同 ...
- 【反反爬】使用Jsoup爬取数据保存Excel
本文主要使用Jsoup爬取XXX房屋信息,抓取一些房屋信息,比如房屋楼盘.户型.价格.地址等信息,然后保存到Excel,便于对比和筛选,选出符合预期的好房. 注意,有些网站有防爬取机制,需要设置动 ...
- js获取当前月的天数
//取得本月天数(实际代码:) var now=new Date(); var d = new Date(now.getFullYear(),now.getMonth()+1,0); var days ...
- 杰哥教你面试之一百问系列:java中高级多线程concurrent的使用
目录 问题1:什么是ConcurrentHashMap?它与HashMap的区别是什么? 问题2:什么是CopyOnWriteArrayList?它适用于什么样的场景? 问题3:什么是Blocking ...
- 文心一言 VS 讯飞星火 VS chatgpt (91)-- 算法导论8.3 4题
四.用go语言,说明如何在 O(n) 时间内,对 0 到 $n^3-1$ 区间内的n个整数进行排序. 文心一言: 在 O(n) 时间内对 0 到 n^3-1 区间内的 n 个整数进行排序,可以使用基数 ...
- 【krpano】淘宝buy+案例
这是一个类似淘宝buy+的案例,是基于krpano全景开发工具二次开发的全景视频.WebVR.360°环物.全景视频热点添加于一身的综合性案例.现在将案例上传网站供krpano技术人员和爱好者大家共同 ...
- Spring Cache + Caffeine实现本地缓存
Caffeine简介 Caffeine是一个高性能,高命中率,低内存占用,near optimal 的本地缓存,简单来说它是 Guava Cache 的优化加强版 依赖 <dependency& ...
- CF1526C2
与简单版的思路完全一致,只需要改一下范围. 可以去看我简单版本的博客. 题目简化和分析: 给您一个数组,在其中选择若干个数使得: 任意前缀和 \(\ge 0\) 数量尽可能的大 我们可以使用贪心策略, ...
- MSFvenom恶意程序生成与利用
MSFvenom 1.1 MSFvenom介绍 MSFvenom是Msfpayload和Msfencode的组合,可以生成各种攻击载荷,并且可以对载荷进行编码.做渗透测试时往往需要将有效负载部署在目标 ...
- 从零用VitePress搭建博客教程(6) -– 第三方组件库的使用和VitePress搭建组件库文档
接上一节:从零用VitePress搭建博客教程(5) - 如何自定义页面模板.给页面添加独有的className和使页面标题变成侧边目录? 九.第三方组件库的使用 我们经常看见UI组件库的文档,这里我 ...