先来一张官方客户端设计图,方便咱们了解客户端的总体思路。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的设计思路 。
盗用官方的一张图来简单说明这个流程: