Apollo源碼閱讀筆記(一)
先來一張官方客戶端設計圖,方便我們了解客戶端的整體思路。
我們在使用Apollo的時候,需要標記@EnableApolloConfig來告訴程序開啟apollo配置,所以這里就以EnableApolloConfig為入口,來看下apollo客戶端的實現邏輯。關於apollo的使用方法詳見 這里
1. 入口 @EnableApolloConfig 注解
@EnableApolloConfig(value={"application","test-yejg"})
默認的namespace是application;
通過@EnableApolloConfig注解,引入了ApolloConfigRegistrar
public class ApolloConfigRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AnnotationAttributes attributes = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(EnableApolloConfig.class.getName()));
String[] namespaces = attributes.getStringArray("value");
int order = attributes.getNumber("order");
// 暫存需要關注的namespaces,后面在PropertySourcesProcessor中會把配置屬性加載env中
PropertySourcesProcessor.addNamespaces(Lists.newArrayList(namespaces), order);
Map<String, Object> propertySourcesPlaceholderPropertyValues = new HashMap<>();
// to make sure the default PropertySourcesPlaceholderConfigurer's priority is higher than PropertyPlaceholderConfigurer
propertySourcesPlaceholderPropertyValues.put("order", 0);
BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, PropertySourcesPlaceholderConfigurer.class.getName(), PropertySourcesPlaceholderConfigurer.class, propertySourcesPlaceholderPropertyValues);
BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, PropertySourcesProcessor.class.getName(), PropertySourcesProcessor.class);
BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, ApolloAnnotationProcessor.class.getName(), ApolloAnnotationProcessor.class);
BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, SpringValueProcessor.class.getName(), SpringValueProcessor.class);
BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, SpringValueDefinitionProcessor.class.getName(), SpringValueDefinitionProcessor.class);
BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, ApolloJsonValueProcessor.class.getName(), ApolloJsonValueProcessor.class);
}
}
注意上面代碼中,通過PropertySourcesProcessor.addNamespaces暫存了namespaces,下面就先沿着 PropertySourcesProcessor來展開
2. 配置設置到environment的過程
PropertySourcesProcessor實現了BeanFactoryPostProcessor,並能獲取到env
public class PropertySourcesProcessor implements BeanFactoryPostProcessor, EnvironmentAware, PriorityOrdered{
...
}
在Spring應用啟動的時候
refresh() –> invokeBeanFactoryPostProcessors(beanFactory) –> PropertySourcesProcessor.postProcessBeanFactory
—> initializePropertySources();
—> initializeAutoUpdatePropertiesFeature(beanFactory);
就這樣,Apollo的PropertySourcesProcessor就被調用起來了。
在它的postProcessBeanFactory方法中依次調用initializePropertySources和initializeAutoUpdatePropertiesFeature,先來看initializePropertySources做了啥事情:
-
將NAMESPACE_NAMES (Multimap<Integer, String>)排序;
-
遍歷排序后的namespaces,依次調用 ConfigService.getConfig(namespace) 獲取配置信息Config;
-
將config封裝成ConfigPropertySource[Apollo的],保存到CompositePropertySource[spring-core的];
此composite名為 ApolloPropertySources
ConfigPropertySource繼承自spring-core的EnumerablePropertySource
代碼:composite.addPropertySource(XXX);
-
循環處理完 NAMESPACE_NAMES 之后,將其清空掉;
-
將前面循環處理好的compositePropertySource加入到env中;
加到env時,判斷env中是否存在 ApolloBootstrapPropertySources是否存在,確保其在第一的位置,而前面循環處理得到的ApolloPropertySources緊隨其后。
相關代碼:
environment.getPropertySources().addAfter(“XXX source name”, composite);
environment.getPropertySources().addFirst(composite);
這部分的邏輯,其實就是佐證了Apollo的設計思路 。
盜用官方的一張圖來簡單說明這個流程: