当前位置:网站首页>手写分布式配置中心(1)
手写分布式配置中心(1)
2022-08-04 23:33: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());
}
边栏推荐
- Develop a SpaceX website based on the Appian low-code platform
- Web安全开发 | 青训营笔记
- Shell expect real cases
- [Cultivation of internal skills of memory operation functions] memcpy + memmove + memcmp + memset (4)
- PID控制器改进笔记之七:改进PID控制器之防超调设定
- 学会反射后,我被录取了(干货)
- The role of @Async annotation and how to implement asynchronous listening mechanism
- [Cultivation of internal skills of string functions] strlen + strstr + strtok + strerror (3)
- 容联云发送短信验证码
- 怎么将自己新文章自动推送给自己的粉丝(巨简单,学不会来打我)
猜你喜欢

360市值四年蒸发3900亿,政企安全能救命吗?

话题 | 雾计算和边缘计算有什么区别?

学会反射后,我被录取了(干货)

【内存操作函数内功修炼】memcpy + memmove + memcmp + memset(四)

uniapp 分享功能-分享给朋友群聊朋友圈效果(整理)

I was rejected by the leader for a salary increase, and my anger rose by 9.5K after switching jobs. This is my mental journey

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

从单体架构迁移到 CQRS 后,我觉得 DDD 并不可怕

The market value of 360 has evaporated by 390 billion in four years. Can government and enterprise security save lives?

一点点读懂Thremal(二)
随机推荐
NebulaGraph v3.2.0 Release Note,对查询最短路径的性能等多处优化
情人节---快来学习一下程序员的专属浪漫吧
功耗控制之DVFS介绍
uniapp 分享功能-分享给朋友群聊朋友圈效果(整理)
使用代理对象执行实现类目标方法异常
招标公告 | 海纳百创公众号运维项目
Nuclei(二)进阶——深入理解workflows、Matchers和Extractors
web3.js
堪称奔驰“理财产品”,空间媲美宝马X5,采用了非常运动的外观
【软件测试】常用ADB命令
truffle
入门3D游戏建模师知识必备
typeScript-promise
Develop a SpaceX website based on the Appian low-code platform
Web安全开发 | 青训营笔记
Service Mesh落地路径
MySQL的安装与卸载
Ab3d.PowerToys and Ab3d.DXEngine Crack
当panic或者die被执行时,或者发生未定义指令时,如何被回调到
未来我们还需要浏览器吗?(feat. 枫言枫语)