使用方式
- 创建配置类,在类增加注解
@Component
@RefreshScop - 类属性上增加注解
@Value
原理分析
依赖包
- spring-cloud-context:2.2.9.RELEASE
- spring-cloud-starter-alibaba-nacos-config:2.2.8.RELEASE
获取nacos更新数据,发送更新事件。
- spring-cloud-starter-alibaba-nacos-config的spring.factories文件配置了NacosConfigAutoConfiguration,在该类配置了Nacos数据刷新的bean。NacosContextRefresher。
2. NacosContextRefresher类。
3. NacosConfigService类,在类中将listener放入到CacheData中,在NacosConfigService的构造函数中创建一个ClientWorker对象,ClientWorker包含一个定时任务,定时获取Nacos数据。
4. ClientWorker类每5秒执行一次executeConfigListen。
5. cacheData调用Listener,此处的Listener有刚才在步骤2 NacosContextRefresher中设置的匿名类,发布RefreshEvent事件。
监听更新事件
- spring-cloud-context包spring.factories中通过EnableAutoConfiguration配置了自动刷新配置类RefreshAutoConfiguration。
- 配置bean对象,RefreshEventListener,ContextRefresher,RefreshScope。当配置更新时发布RefreshEvent事件。RefreshEventListener监听到该事件调用onApplicationEvent方法,onApplicationEvent会调用ContextRefresher的refresh方法,在refresh方法中检查ConfigurableApplicationContext的环境ConfigurableEnvironment中的属性变化,更新ConfigurableEnvironment中变化的属性值,清除RefreshScope中缓存的配置类对象。在获取配置类bean对象时由于RefreshScope的缓存被清楚了,所以会从ConfigurableEnvironment中获取属性值重新创建配置类对象,达到动态更新配置的目的。
- 环境变量的值获取是通过NacosPropertySourceLocator获取的,在NacosConfigBootstrapConfiguration中配置。
配置类的创建
- RefreshScopeBeanDefinitionEnhancer的postProcessBeanDefinitionRegistry方法中生成类的代理,配置为ScopedProxyFactoryBean
- jdk动态代理JdkDynamicAopProxy,targetSource是前面一个步骤中设置的scopedTargetSource。
ProxyFactory pf = new ProxyFactory();
pf.copyFrom(this);
pf.setTargetSource(this.scopedTargetSource);
3. scopedTargetSource 的类型为SimpleBeanTargetSource 。获取bean对象。
总结:
1 定时任务获取通过ClientWorker获取Nacos配置,对获取的配置md5运算与目前的配置的md5比较,如配置发生变化则发送RefreshEvent事件。
2 RefreshEventListener监听到该事件则将ApplicationContext中的环境变量做比较(新创建了一个环境变量,使用了SpringApplication的run方法重新对环境变量进行了初始化,使用NacosPropertySourceLocator重新获取了Nacos配置值,然后比较环境变量更新前后的差异),如果发生变化则清空RefreshScope中缓存的配置类Bean。
3 每次在获取配置的时都会通过代理调用getTarget方法获取被代理的配置类,先从RefreshScope中获取,没有则重新创建。