先來一張官方客戶端設計圖,方便咱們瞭解客戶端的總體思路。java
咱們在使用Apollo的時候,須要標記@EnableApolloConfig來告訴程序開啓apollo配置,因此這裏就以EnableApolloConfig爲入口,來看下apollo客戶端的實現邏輯。關於apollo的使用方法詳見 這裏git
@EnableApolloConfig(value={"application","test-yejg"})
默認的namespace是application;
經過@EnableApolloConfig註解,引入了ApolloConfigRegistrargithub
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來展開spring
PropertySourcesProcessor實現了BeanFactoryPostProcessor,並能獲取到envapp
public class PropertySourcesProcessor implements BeanFactoryPostProcessor, EnvironmentAware, PriorityOrdered{ ... }
在Spring應用啓動的時候ide
refresh() –> invokeBeanFactoryPostProcessors(beanFactory) –> PropertySourcesProcessor.postProcessBeanFactorypost
—> initializePropertySources();spa
—> initializeAutoUpdatePropertiesFeature(beanFactory);設計
就這樣,Apollo的PropertySourcesProcessor就被調用起來了。code
在它的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的設計思路 。
盜用官方的一張圖來簡單說明這個流程: