源码分析:apollo、nacos 读取配置动态刷新

apollo—代码
nacos—代码

apollo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
------------------------------------------------------------------------------------
结论(放在上面):@Value 会刷新,Environment获取也会刷新,@ApolloConfigChangeListener 标记方法来监听ConfigChangeEvent事件
------------------------------------------------------------------------------------
启动:

# 手动 @EnableApolloConfig
# 自动 apollo-client-1.1.0.jar / META-INF / spring.factories / ApolloAutoConfiguration
-> 注册 @Bean ConfigPropertySourcesProcessor
-> postProcessBeanDefinitionRegistry (方法)
-> SpringValueProcessor @Value更新-属性
-> ApolloAnnotationProcessor @ApolloConfigChangeListener触发-方法
-> postProcessBeanFactory (方法-继承于父类 extends PropertySourcesProcessor)
-> initializePropertySources (添加 ApolloPropertySources)
-> initializeAutoUpdatePropertiesFeature (添加广播 AutoUpdateConfigChangeListener @Value更新-属性)
------------------------------------------------------------------------------------
仓库工厂类 DefaultConfigFactory
依赖关系 1.RemoteConfigRepository -> 2.LocalFileConfigRepository -> 3.DefaultConfig

1. RemoteConfigRepository.onLongPollNotified (长轮询通知)
-> sync (HTTP GET 获取最新配置)
-> fireRepositoryChange 下游
2. LocalFileConfigRepository.onRepositoryChange
-> persistLocalCacheFile (持久化本地文件)
-> fireRepositoryChange 下游
3. DefaultConfig.onRepositoryChange
-> updateAndCalcConfigChanges (原子更新 properties)
-> fireConfigChange(ConfigChangeEvent)
-> for m_listeners.onChange
=> AutoUpdateConfigChangeListener.onChange @Value更新-属性
=> ApolloAnnotationProcessor.processMethod @ApolloConfigChangeListener触发-方法
------------------------------------------------------------------------------------

nacos

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
---------------------------------------------------------------------
参考: Spring-Cloud源码:@RefreshScope ===> https://blog.csdn.net/qq_42187215/article/details/130969120
---------------------------------------------------------------------
apollo 会自动刷新(刷新属性值)
Nacos 不会自动刷新(需加 @RefreshScope,而且调用刷新的值,需要是 方法调用才可以)


@NacosValue 测试失败
抽象类 public protected 都测试成功
Nacos要配合 @RefreshScope 才能刷新(方法调用)

环境变量 -> Spring环境中获取,每次都成功
---------------------------------------------------------------------
spring-cloud-context-3.1.1 / META-INF / spring.factories
RefreshAutoConfiguration
RefreshScope extends GenericScope
-> super.setName("refresh");
-> GenericScope.postProcessBeanFactory --> beanFactory.registerScope(this.name, this);// "refresh" RefreshScope
LegacyContextRefresher (RefreshScope) @ConditionalOnBootstrapEnabled √√√
ConfigDataContextRefresher (RefreshScope) @ConditionalOnBootstrapDisabled ×××
RefreshEventListener (LegacyContextRefresher)
-> refreshEnvironment() 与 refreshAll()

@RefreshScope
===> @Scope("refresh") ---> 默认 NO --- ScopedProxyMode proxyMode() default ScopedProxyMode.DEFAULT;
===> ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS;
ClassPathBeanDefinitionScanner.doScan
---> candidate.setScope(scopeMetadata.getScopeName());
---> AnnotationConfigUtils.applyScopedProxyMode ---> ScopedProxyUtils.createScopedProxy
-> String targetBeanName = getTargetBeanName(originalBeanName); --- "scopedTarget." + originalBeanName;// scopedTarget.testController
-> RootBeanDefinition proxyDefinition = new RootBeanDefinition(ScopedProxyFactoryBean.class);
-> targetDefinition.setAutowireCandidate(false);// 原始Bean定义 不能被依赖
-> registry.registerBeanDefinition(targetBeanName, targetDefinition);// 注册 "scopedTarget.testController",原始Bean定义
-> return new BeanDefinitionHolder(proxyDefinition, originalBeanName, definition.getAliases());// 注册 "testController",代理Bean定义
GenericScope.postProcessBeanDefinitionRegistry
---> LockedScopedProxyFactoryBean (实现 FactoryBean---getObject()---proxy === 别人依赖它,都会依赖 proxy 代理对象,每次从容器中获取新的对象)
---> LockedScopedProxyFactoryBean.setBeanFactory ---> ScopedProxyFactoryBean.setBeanFactory
-> this.scopedTargetSource.setBeanFactory(beanFactory);
-> pf.setTargetSource(this.scopedTargetSource);// SimpleBeanTargetSource
-> this.proxy = pf.getProxy(cbf.getBeanClassLoader());// CGLIB 代理对象

CglibAopProxy.DynamicAdvisedInterceptor.intercept
-> TargetSource targetSource = this.advised.getTargetSource();// SimpleBeanTargetSource
-> target = targetSource.getTarget();// SimpleBeanTargetSource.getTarget ------> getBeanFactory().getBean(getTargetBeanName());
-> retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
-> LockedScopedProxyFactoryBean.invoke
-> return ReflectionUtils.invokeMethod(method, advised.getTargetSource().getTarget(), invocation.getArguments());

AbstractBeanFactory.doGetBean -> scope='refresh'
GenericScope.get
-> this.cache.put ---> this.cache.putIfAbsent(name, value);
-> return value.getBean(); ---> if (this.bean == null) { this.bean = this.objectFactory.getObject(); }
AbstractAutowireCapableBeanFactory.doCreateBean
-> populateBean
-> postProcessProperties Autowired处理器填充属性 最终环境变量里面解析占位符

只有发布的时候,才会刷新 this,重新创建
===> Controller拦截器 getBean 会判断缓存,如果有就直接返回,没有才创建
===> 只有 Nacos配置更新,长轮询发送 RefreshEvent,从而 refreshEnvironment(),scope.refreshAll()---destroy()---cache.clear() 清空缓存,下次请求重新创建
---------------------------------------------------------------------

ClientWorker.LongPollingRunnable.run
-> cacheData.checkListenerMd5();
-> listener.receiveConfigInfo(contentTmp); ---> AbstractSharedListener.receiveConfigInfo
NacosContextRefresher (NacosConfigAutoConfiguration)
-> registerNacosListener configService.addListener
-> RefreshEvent

RefreshEventListener.onApplicationEvent (RefreshAutoConfiguration)
-> handle((RefreshEvent) event);
-> this.refresh.refresh() (LegacyContextRefresher)
-> ContextRefresher.refresh
Set<String> keys = refreshEnvironment();
this.scope.refreshAll(); ---> super.destroy(); GenericScope.destroy()
-> this.cache.clear()
-> wrapper.destroy(); this.bean = null;

@RefreshScope 修饰的类,调用方法时,会被 CGLIB 代理
---------------------------------------------------------------------