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做了啥事情:

  1. 将NAMESPACE_NAMES (Multimap<Integer, String>)排序;

  2. 遍历排序后的namespaces,依次调用 ConfigService.getConfig(namespace) 获取配置信息Config;

  3. 将config封装成ConfigPropertySource[Apollo的],保存到CompositePropertySource[spring-core的];

    ​ 此composite名为 ApolloPropertySources

    ​ ConfigPropertySource继承自spring-core的EnumerablePropertySource

    ​ 代码:composite.addPropertySource(XXX);

  4. 循环处理完 NAMESPACE_NAMES 之后,将其清空掉;

  5. 将前面循环处理好的compositePropertySource加入到env中;

    ​ 加到env时,判断env中是否存在 ApolloBootstrapPropertySources是否存在,确保其在第一的位置,而前面循环处理得到的ApolloPropertySources紧随其后。

    ​ 相关代码:

    ​ environment.getPropertySources().addAfter(“XXX source name”, composite);

    ​ environment.getPropertySources().addFirst(composite);

这部分的逻辑,其实就是佐证了Apollo的设计思路

盗用官方的一张图来简单说明这个流程:

Apollo源码阅读笔记(一)的更多相关文章

  1. Apollo源码阅读笔记(二)

    Apollo源码阅读笔记(二) 前面 分析了apollo配置设置到Spring的environment的过程,此文继续PropertySourcesProcessor.postProcessBeanF ...

  2. CI框架源码阅读笔记5 基准测试 BenchMark.php

    上一篇博客(CI框架源码阅读笔记4 引导文件CodeIgniter.php)中,我们已经看到:CI中核心流程的核心功能都是由不同的组件来完成的.这些组件类似于一个一个单独的模块,不同的模块完成不同的功 ...

  3. CI框架源码阅读笔记4 引导文件CodeIgniter.php

    到了这里,终于进入CI框架的核心了.既然是“引导”文件,那么就是对用户的请求.参数等做相应的导向,让用户请求和数据流按照正确的线路各就各位.例如,用户的请求url: http://you.host.c ...

  4. CI框架源码阅读笔记3 全局函数Common.php

    从本篇开始,将深入CI框架的内部,一步步去探索这个框架的实现.结构和设计. Common.php文件定义了一系列的全局函数(一般来说,全局函数具有最高的加载优先权,因此大多数的框架中BootStrap ...

  5. CI框架源码阅读笔记2 一切的入口 index.php

    上一节(CI框架源码阅读笔记1 - 环境准备.基本术语和框架流程)中,我们提到了CI框架的基本流程,这里再次贴出流程图,以备参考: 作为CI框架的入口文件,源码阅读,自然由此开始.在源码阅读的过程中, ...

  6. 源码阅读笔记 - 1 MSVC2015中的std::sort

    大约寒假开始的时候我就已经把std::sort的源码阅读完毕并理解其中的做法了,到了寒假结尾,姑且把它写出来 这是我的第一篇源码阅读笔记,以后会发更多的,包括算法和库实现,源码会按照我自己的代码风格格 ...

  7. Three.js源码阅读笔记-5

    Core::Ray 该类用来表示空间中的“射线”,主要用来进行碰撞检测. THREE.Ray = function ( origin, direction ) { this.origin = ( or ...

  8. PHP源码阅读笔记一(explode和implode函数分析)

    PHP源码阅读笔记一一.explode和implode函数array explode ( string separator, string string [, int limit] )此函数返回由字符 ...

  9. AQS源码阅读笔记(一)

    AQS源码阅读笔记 先看下这个类张非常重要的一个静态内部类Node.如下: static final class Node { //表示当前节点以共享模式等待锁 static final Node S ...

随机推荐

  1. EF6学习笔记(六续) 复杂数据模型建表测试

    测试以下几种模型关系: 1对1或0  . 1对多  . 多对多 1 对 1 或 0 如果直接定义两个模型,相互直接增加导航属性,会提示错误,必须为这个对应关系设定主副关系: public class ...

  2. 嵌入式FIFO核的调用

    本次设计源码下载地址:http://download.csdn.net/detail/noticeable/9915523 课程目标:学习调用quartus II 软件的FIFO(先进先出)IP核,并 ...

  3. fork()函数、进程表示符、进程位置

    linux.centos6.5 fork()函数:作用于创建子进程.返回值有两个,一个是向父进程返回它的pid,一个是返回0: eg1: #include<stdio.h> #includ ...

  4. 浅谈ESB中的DataRow、DataSet、DataBag 、DataBox

    1 背景概述 笔者在学习公司产品AEAI ESB 的时候经常需要从数据库获取信息并将数据信息保存到一个结果变量中,为统计分析提供特定格式的数据以及跨数据库同步数据时通常会用到DataRow.DataS ...

  5. Objective-C优缺点

    优点: 1:Category,使用category可以在不改变原来类的同时为类增加新的方法或者重写原来类的方法实现(使用runtime方法还可以在分类中实现方法交换和添加属性操作) 2:运行时 动态识 ...

  6. git checkout tags with the same name as a branch

    显式指定某个 tag git checkout refs/tags/ git checkout refs/tags/v0.1 显式指定某个 branch git checkout refs/heads ...

  7. HTTP 总结

    一.概念 特性 1. HTTP协议用于客户端和服务端之间的通信 2. 通过请求和响应的交互达成通信 : HTTP协议规定,请求从客户端发出,最后服务器端响应请求并返回,也就是说,肯定是从客户端开始建立 ...

  8. [Mac]macOS Mojave :发现 Mac 的新功能。

    1.深色模式 换种颜色看 Mac “深色模式”为桌面和内建应用带来更生动的外观,可让您轻松专注于最重要的内容. 若要在浅色和深色外观之间切换,请打开“系统偏好设置”并点按“通用”. 2.叠放 整理桌面 ...

  9. bootstrap使用之多个弹窗和拖动效果[开发篇]

    有时开发一些特效,自己感觉挺爽的,像操作自己电脑一样操作你的网页,这里就介绍一个使用bootstrap的一点多窗口和拖动效果吧! 这里,我们不使用静态打开的的方式,low...,1.添加一个a链接 触 ...

  10. Python+Excel+Unittest+HTMLTestRunner实现数据驱动接口自动化测试(二)

    因为小白,这2天研究了好久才算是搞好.先附上一个测试完成后邮件的截图: 上一篇有提到: unittest中实际运行了一个接口的很多条用例,而报告中只会有一条记录.这是因为unittest test c ...