业务需求

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配置中心实现配置动态刷新的更多相关文章

  1. 手撸一个SpringBoot的Starter,简单易上手

    前言:今天介绍一SpringBoot的Starter,并手写一个自己的Starter,在SpringBoot项目中,有各种的Starter提供给开发者使用,Starter则提供各种API,这样使开发S ...

  2. 看了 Spring 官网脚手架真香,也撸一个 SpringBoot DDD 微服务的脚手架!

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 为什么我们要去造轮子? 造轮子的核心目的,是为了解决通用共性问题的凝练和复用. 虽然 ...

  3. 手撸一个SpringBoot-Starter

    1. 简介 通过了解SpringBoot的原理后,我们可以手撸一个spring-boot-starter来加深理解. 1.1 什么是starter spring官网解释 starters是一组方便的依 ...

  4. 手撸一个springsecurity,了解一下security原理

    手撸一个springsecurity,了解一下security原理 转载自:www.javaman.cn 手撸一个springsecurity,了解一下security原理 今天手撸一个简易版本的sp ...

  5. 【手撸一个ORM】MyOrm的使用说明

    [手撸一个ORM]第一步.约定和实体描述 [手撸一个ORM]第二步.封装实体描述和实体属性描述 [手撸一个ORM]第三步.SQL语句构造器和SqlParameter封装 [手撸一个ORM]第四步.Ex ...

  6. C#基于Mongo的官方驱动手撸一个Super简易版MongoDB-ORM框架

    C#基于Mongo的官方驱动手撸一个简易版MongoDB-ORM框架 如题,在GitHub上找了一圈想找一个MongoDB的的ORM框架,未偿所愿,就去翻了翻官网(https://docs.mongo ...

  7. 五分钟,手撸一个Spring容器!

    大家好,我是老三,Spring是我们最常用的开源框架,经过多年发展,Spring已经发展成枝繁叶茂的大树,让我们难以窥其全貌. 这节,我们回归Spring的本质,五分钟手撸一个Spring容器,揭开S ...

  8. .Net Core 自定义配置源从配置中心读取配置

    配置,几乎所有的应用程序都离不开它..Net Framework时代我们使用App.config.Web.config,到了.Net Core的时代我们使用appsettings.json,这些我们再 ...

  9. spring cloud 系列第8篇 —— config+bus 分布式配置中心与配置热刷新 (F版本)

    源码Gitub地址:https://github.com/heibaiying/spring-samples-for-all 一.config 简介 spring cloud config 分为服务端 ...

  10. 通过 Netty、ZooKeeper 手撸一个 RPC 服务

    说明 项目链接 微服务框架都包括什么? 如何实现 RPC 远程调用? 开源 RPC 框架 限定语言 跨语言 RPC 框架 本地 Docker 搭建 ZooKeeper 下载镜像 启动容器 查看容器日志 ...

随机推荐

  1. CI+JUnit5并发单测机制创新实践

    一. 现状·问题 针对现如今高并发场景的业务系统,"并发问题" 终归是必不可少的一类(占比接近10%),每次出现问题和事故后,需要耗费大量人力成本排查分析并修复.那如果能在事前尽可 ...

  2. chatglm2-6b模型在9n-triton中部署并集成至langchain实践

    一.前言 近期, ChatGLM-6B 的第二代版本ChatGLM2-6B已经正式发布,引入了如下新特性: ①. 基座模型升级,性能更强大,在中文C-Eval榜单中,以51.7分位列第6: ②. 支持 ...

  3. 实在智能TARS-RPA-Agent,业界首发的产品级大模型Agent有何非凡之处?

    融合LLM的RPA进化到什么程度? AIGC如何借AI Agent落地? 像生成文本一样生成流程的ChatRPA,能够提升RPA新体验? 边探索边创建的ChatRPA,能否破解RPA与LLM融合难题? ...

  4. Linux 内核音频数据传递主要流程 (下)

    来而不往非礼也.前面看到了用户空间应用程序和 DMA buffer 之间交换数据,并更新 runtime->control->appl_ptr 指针的过程,这里看一下硬件设备驱动程序在完成 ...

  5. .NET API 中的 FromRoute、FromQuery、FromBody 用法

    原文链接:https://www.cnblogs.com/ysmc/p/17663663.html 最近技术交流群里,还有不少小伙伴不知道 FromRoute.FromQuery.FromBody 这 ...

  6. C++算法之旅、04 基础篇 | 第一章

    常用代码模板1--基础算法 - AcWing ios::sync_with_stdio(false) 提高 cin 读取速度,副作用是不能使用 scanf 数据输入规模大于一百万建议用scanf 快速 ...

  7. sqoop1.4.7完全支持Hadoop3.x, Hive3.x Hbase2.x

    已经修改好 保存至云盘 自己下载 花了时间的,记得关注我... 链接:https://pan.xunlei.com/s/VNe6P6Tm1A9Q-RG5GByN08rdA1# 提取码:5nke 复制这 ...

  8. zabbix 警报推送至企业微信(图文版)

    新增Python脚本 # encoding: utf-8 import sys import requests import json import os import time import re ...

  9. MySQL 表分区使用实践

    在使用 MySQL 8.0 表分区时,需要注意以下一些关键事项和最佳实践: 支持的存储引擎: MySQL 8.0 表分区仅支持一些特定的存储引擎,如 InnoDB 和 NDB(NDB 是 MySQL ...

  10. 「luogu - P3158」「cqoi 2011」放棋子

    link. 解读一下,大概就是一种颜色放进去就会占据一行一列,dp 状态就好想了:\(f_{i,j,k}\) 表示恰好用完前 \(k\) 种颜色的所有棋子,占据了 \(i\) 行 \(j\) 列的方案 ...