从0到1手写配置中心config之基于数据库的分布式锁

  1. DistributedLocks实现
  • 自动注入数据源。创建连接,保证不影响其他连接。
  • locked原子变量判断是否加锁成功;
  • Executor 定时任务,尝试获取锁。

图片

  1. init()初始化方法

使用注解@PostConstruct初始化,使用数据源创建连接。

开启定时任务,每隔5秒执行一次。

图片

  1. tryLock()方法

尝试获取锁,获取成功,locked=true,否则为false。

图片

  1. lock() 加锁
  • 关闭自动提交事务;
  • 设置事务隔离级别为RC;
  • 设置锁超时时间innodb_lock_wait_timeout为5秒;
  • 执行锁定语句for update加锁
  • 事务不要commit或rollback,否则锁就释放了
  • 根据locked状态判断是第一次获取到锁,还是后续的锁重入。

图片

  1. closed()方法

使用@PreDestroy注解销毁bean时,连接回滚,并关闭。

图片

  1. 测试
  • 分别用端口9129和9130启动config-server

假如9129先启动,观察日志成功获取到锁了,并在定时任务重不断重入。

图片

  • 9130端口后启动,不会获取到锁,等待5秒后,抛出超时异常。

图片

  • 关闭9129,观察9130。可以自动获取到锁。

图片

锁状态locked表示已经持有

图片

源码:https://github.com/midnight2104/midnight-config/tree/v5

从0到1手写配置中心config之spring value热更新

  1. 定义SpringValueProcessor处理类
  • 实现BeanPostProcessor后置处理器接口,扫描所有的Spring value,保存起来。
  • 实现ApplicationListener接口,在配置变更时,更新所有的spring value

图片

  1. 实现BeanPostProcessor后置处理器接口

实现postProcessBeforeInitialization()方法。通过工具类找到所有带有@Value的bean,遍历每个字段。通过helper工具类抽取注解上面的表达式,构建SpringValue对象并保存起来。

图片

使用SpringValue对象封装@Value注解信息。

图片

一个SpringValue对象如下:

图片

  1. 实现onApplicationEvent方法
  • 事件变更时,自动实现该方法;
  • 从前面保存的holder中获取SpringValues;
  • 遍历集合,解析获取属性值;
  • 通过反射重新赋值。

图片

  1. 测试
  • 启动 config-server
  • 启动config-client

初始值如下:都是dev100

图片

更新配置中心的值

图片

观察config-demo的日志

图片

再次获取值,就已经动态发生了变化。

图片

源码:https://github.com/midnight2104/midnight-config/tree/v4

从0到1手写配置中心config之@configurationproperties热更新

  1. 在PropertySourcesProcessor中,需要通过http从config-server获取配置。

图片

  1. 使用ConfigMeta包装服务信息

图片

  1. 在MidnightConfigService接口中添加默认实现类
  • 继承MidnightRepositoryChangeListener接口;
  • 获取默认的MidnightRepository;
  • 创建MidnightConfigServiceImpl实现类;
  • 添加listener

图片

  1. 定义MidnightRepositoryChangeListener,用于事件监听的回调接口
  • onChange() 执行方法
  • ChangeEvent变动事件,传递参数

图片

  1. 定义MidnightRepository接口
  • 提供默认实现类
  • getConfig()获取配置
  • addListener()添加监听器

图片

  1. MidnightRepositoryImpl实现从server获取配置
  • meta保存服务配置源信息;
  • versionMap保存server版本号,用于比较本地和远程版本信息,用于比对配置是否发生变化;
  • configMap保存一个ns服务下所有配置信息;
  • executor定时任务,监听服务端配置是否发生变化;
  • listeners保存监听器。

图片

  1. findAll()接口

发起http请求,从config-server获取所有配置信息。

图片

  1. heartbeat() 心跳检测
  • 发起http请求,从配置中心服务端获取最新版本信息;
  • 当远程版本信息大于本地版本信息时,说明配置发生了变化。
  • 保存最新版本信息;
  • 从配置中心重新获取所有配置信息;
  • 保存最新的配置信息;
  • 发布配置发生变更事件

图片

  1. onChange() 发布事件
  • 更新本地最新配置
  • 通过Spring发布环境变更事件。事件类EnvironmentChangeEvent来自于SpringCloud,解决微服务架构下配置热更新问题。

图片

  1. 重新绑定配置

当EnvironmentChangeEvent事件发布之后,会重新绑定PropertySource,调用getProperty()方法获取最新配置。

图片

  • @ConfigurationProperties 中的属性就会被更新

图片

  1. 测试
  • 启动config-server
  • 启动config-client
  • 观察日志,最开始的值如下

图片

  • 更新这两个值后,再观察日志。

发现版本发生了变化,重新获取了配置,并发布了EnvironmentChangeEvent事件。

图片

  • 两个值已经被更新了

图片

源代码:

https://github.com/midnight2104/midnight-config/tree/v3