当前位置:网站首页>Handwritten Distributed Configuration Center (1)
Handwritten Distributed Configuration Center (1)
2022-08-04 23:42:00 【InfoQ】
1 什是分布式配置中心
1.1 分布式配置中心有哪些组成
1.1.1, 有一个界面能操作配置
1.1.2, 数据能够持久化(防止丢失,服务下线在启动配置还是存在的)
1.1.3, 存在客户端和服务端, 客户端主动去拉去数据或者服务端主动推送数据. 并且刷新本机的配置.(核心)
1.1.4, 一些管理界面的操作日志, 权限系统等.
2,市面上主流的配置中心
2.1 阿里的 nacos
2.2 nacos 的原理,就是service 监控配置是否发生改变,通过长链接在发送给客户端
2.3 携程的Apollo
2.3 spirgcloud config
2.4 百度disconf
3如何实现自己的分布式配置中心
3.1 动态修改本地@Value注解的配置
3.2 在不同的bean 中, 相同的value 怎么同时修改.
4 具体思路
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment,
SpringApplication application) {
//怎么加载资源
addPropertySources(environment, application.getResourceLoader());
}
protected void addPropertySources(ConfigurableEnvironment environment,
ResourceLoader resourceLoader) {
RandomValuePropertySource.addToEnvironment(environment);
// 把资源给load 到环境变量里面
new Loader(environment, resourceLoader).load();
}
// 再用 propertySource 解析器给解析
Loader(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
this.environment = environment;
this.placeholdersResolver = new PropertySourcesPlaceholdersResolver(
this.environment);
this.resourceLoader = (resourceLoader != null) ? resourceLoade
: new DefaultResourceLoader();
this.propertySourceLoaders = SpringFactoriesLoader.loadFactories(
PropertySourceLoader.class, getClass().getClassLoader());
}
4.1 代码实现
@Autowired
ConfigurableEnvironment configurableEnvironment;
@Autowired
Environment environment;
@Test
public void test() {
String name = environment.getProperty("name");
System.out.printf("动态加载之前" +name);
Map<String,String> map = new HashMap<>();
map.put("name","嘟嘟");
configurableEnvironment.getPropertySources().addLast(
new OriginTrackedMapPropertySource("xxxx.xml", map)
);
String property = environment.getProperty("name");
System.out.printf("动态加载之后" +property);
}
4.1.2 单元测试
4.2 代码实现
public static void refreshBean(Object bean, ConfigurablePropertyResolver propertyResolver) {
// 定义EL表达式解释器
SpelExpressionParser spelExpressionParser = new SpelExpressionParser();
TemplateParserContext templateParserContext= new TemplateParserContext();
String keyResolver, valueResolver = null;
Object parserValue;
// 获取真实对象属性
Field[] declaredFields = bean.getClass().getDeclaredFields();
boolean cglib = Arrays.stream(declaredFields).anyMatch(x -> x.getName().contains("CGLIB"));
// 如果是cglib 代理找其父类
if(cglib){
declaredFields = bean.getClass().getSuperclass().getDeclaredFields();
}
// 遍历Bean实例所有属性
for (Field field : declaredFields) {
// 判断field是否含有@Value注解
if (field.isAnnotationPresent(Value.class)) {
// 读取Value注解占位符
keyResolver = field.getAnnotation(Value.class).value();
try {
// 读取属性值
valueResolver = propertyResolver.resolveRequiredPlaceholders(keyResolver);
// EL表达式解析
// 兼容形如:@Value("#{'${codest.five.url}'.split(',')}")含有EL表达式的情况
Expression expression = spelExpressionParser.parseExpression(valueResolver, templateParserContext);
if(field.getType() == Boolean.class){
parserValue =Boolean.valueOf(expression.getValue().toString());
}
else if(field.getType() == Integer.class){
parserValue =Integer.valueOf(expression.getValue().toString());
}
else if(field.getType() == Long.class){
parserValue =Long.valueOf(expression.getValue().toString());
}else {
parserValue = expression.getValue(field.getType());
}
} catch (IllegalArgumentException e) {
continue;
}
// 判断配置项是否存在
if (Objects.nonNull(valueResolver)) {
field.setAccessible(true);
try {
field.set(bean, parserValue);
continue;
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
4.2.1 单元测试
@Autowired
ConfigurableEnvironment configurableEnvironment;
@Autowired
ConfigurablePropertyResolver configurablePropertyResolver;
@Autowired
Person person;
@Test
public void test() {
System.out.printf("动态加载之前" +person.getName());
Map<String,Object> map = new HashMap<>();
map.put("name","嘟嘟");
configurableEnvironment.getPropertySources().forEach( x->{
if (x instanceof OriginTrackedMapPropertySource ) {
Map<String,Object> map1 = (Map<String, Object>) x.getSource();
map1.putAll(map);
}
}
);
refreshBean(person,configurablePropertyResolver);
System.out.printf("动态加载之后" +person.getName());
}
边栏推荐
- Implementation principle of golang coroutine
- typeScript-promise
- .net(C#)获取两个日期间隔的年月日
- 2022牛客暑期多校训练营5(BCDFGHK)
- After another 3 days, I have sorted out 90 NumPy examples, and I can't help but bookmark it!
- 为何越来越多人选择进入软件测试行业?深度剖析软件测试的优势...
- mysql基础
- The Go Programming Language (Introduction)
- kernel问题定位手段总结
- Security software Avast and Symantec NortonLifeLock merge with UK approval, market value soars 43%
猜你喜欢

Will we still need browsers in the future?(feat. Maple words Maple language)

web3.js

truffle

【软件测试】常用ADB命令

深度|医疗行业勒索病毒防治解决方案

uniapp横向选项卡(水平滚动导航栏)效果demo(整理)

kernel hung_task死锁检测机制原理实现

How to burn the KT148A voice chip into the chip through the serial port and the tools on the computer

功耗控制之DVFS介绍

游戏3D建模入门,有哪些建模软件可以选择?
随机推荐
SQL关联表更新
Linear DP (bottom)
情人节---快来学习一下程序员的专属浪漫吧
社区分享|腾讯海外游戏基于JumpServer构建游戏安全运营能力
3年,从3K涨薪到20k?真是麻雀啄了牛屁股 — 雀食牛逼呀
深度|医疗行业勒索病毒防治解决方案
一、爬虫基本概念
Since a new byte of 20K came out, I have seen what the ceiling is
小黑leetcode之旅:95. 至少有 K 个重复字符的最长子串
Implementation principle of golang coroutine
365天深度学习训练营-学习线路
为何越来越多人选择进入软件测试行业?深度剖析软件测试的优势...
Kernel函数解析之kernel_restart
一点点读懂Thremal(二)
当panic或者die被执行时,或者发生未定义指令时,如何被回调到
MySQL基础篇【聚合函数】
一点点读懂cpufreq(二)
三大技巧让你成功入门3D建模,零基础小白必看
uniapp动态实现滑动导航效果demo(整理)
MySQL增删改查基础