人间日常

所行皆过往,所愿皆成真

正在加载今日诗词....

从Apollo动态配置原理学Spring(一)

最近工作碰到需要写一个类似携程Apollo的动态配置功能,以此系统学习该原理,熟练掌握下Spring的各种机制

Apollo动态配置原理简述

Apollo配置中心动态生效机制,是基于Http长轮询请求和Spring扩展机制实现的,在Spring容器启动过程中,Apollo通过自定义的BeanPostProcessorBeanFactoryPostProcessor將参数中包含${…}占位符和@Value注解的Bean注册到Apollo框架中定义的注册表中。然后通过Http长轮询不断的去获取服务端的配置信息,一旦配置发生变化,Apollo会根据变化的配置的Key找到对应的Bean,然后修改Bean的属性,从而实现了配置动态生效的特性。

需要注意的是,Apollo在配置变化后,只能修改Bean的属性,例如我们数据源的属性发生变化,新创建的Connection对象是没问题的,但是连接池中已经创建的Connection对象相关信息是不能动态修改的,所以依然需要重启应用。

其中涉及到的Spring的扩展机制有:

  • BeanFactoryPostProcessor
  • BeanPostProcessor
  • BeanDefinitionRegistry
  • PropertySource
  • ImportBeanDefinitionRegistrar
  • PropertySourcesPlaceholderConfigurer

其中每一个都是非常关键的点,我们后续会一一进行学习。

Apollo启动过程

首先,我们先看一张图:

Apollo启动图

  1. Spring启动,扫描bean,将相关变量参数注册到Apollo属性注册表

  2. 通过RemoteConfigRepository获取配置,持久化本地,后续读取从本地读取,通过PropertySourcesProcessor执行如下步骤

    (1)根据命名空间从配置中心获取配置信息,创建RemoteConfigRepository和LocalFileConfigRepository对象。RemoteConfigRepository表示远程配置中心资源,LocalFileConfigRepository表示本地缓存配置资源。

    (2)LocalFileConfigRepository对象缓存配置信息到C:\opt\data 或者/opt/data目录

    (3)RemoteConfigRepository开启HTTP长轮询请求定时任务,默认2s请求一次。

    (4)將本地缓存配置信息转换为PropertySource对象(Apollo自定义了Spring的PropertySource),加载到Spring的Environment对象中。至此静态配置就已经加入到环境变量中

    (5)將自定义的ConfigPropertySource注册为观察者。一旦RemoteConfigRepository发现远程配置中心信息发生变化,ConfigPropertySource对象会得到通知。

  3. 通过一个自定义监听器,监听对应事件

  4. 后续通过长轮询请求监听到配置变化,根据配置读取注册表里面的key和对应的bean,通过反射修改bean对应属性值

Apollo扩展点

  1. PropertySourcesProcessor初始化Apollo配置、接入Spring environment,初始化Apollo监听器
  2. ApolloAnnotationProcessor提供Apollo一些注解支持@ApolloConfig@ApolloConfigChangeListener
  3. SpringValueProcessor提供对@Value动态生效能力 针对实例bean
  4. SpringValueDefinitionProcessor提供对@Value动态生效能力 针对bean定义
  5. ApolloJsonValueProcessor提供对@ApolloJsonValue 支持

上述分别对应使用Spring的扩展能力BeanFactoryPostProcessorBeanPostProcessorBeanPostProcessorBeanFactoryPostProcessorBeanDefinitionRegistryPostProcessorBeanPostProcessor

我们这个系列也会对apollo基于spring提供的扩展点来嵌入自己的能力。主要为BeanFactoryPostProcessor、BeanPostProcessor这两个扩展点;先简单说一下:只需要知道,BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor在生成所有beandefinition之后调用,而BeanPostProcessor在通过beandefinition实例化bean的过程中调用即可。

那这些实现我们就下篇见了!!!

关注我

湘ICP备2020021380号-1
© 2014 - 2024 SIWEN.PENG