Apollo源码阅读笔记(一)
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的设计思路 。
盗用官方的一张图来简单说明这个流程:

Apollo源码阅读笔记(一)的更多相关文章
- Apollo源码阅读笔记(二)
Apollo源码阅读笔记(二) 前面 分析了apollo配置设置到Spring的environment的过程,此文继续PropertySourcesProcessor.postProcessBeanF ...
- CI框架源码阅读笔记5 基准测试 BenchMark.php
上一篇博客(CI框架源码阅读笔记4 引导文件CodeIgniter.php)中,我们已经看到:CI中核心流程的核心功能都是由不同的组件来完成的.这些组件类似于一个一个单独的模块,不同的模块完成不同的功 ...
- CI框架源码阅读笔记4 引导文件CodeIgniter.php
到了这里,终于进入CI框架的核心了.既然是“引导”文件,那么就是对用户的请求.参数等做相应的导向,让用户请求和数据流按照正确的线路各就各位.例如,用户的请求url: http://you.host.c ...
- CI框架源码阅读笔记3 全局函数Common.php
从本篇开始,将深入CI框架的内部,一步步去探索这个框架的实现.结构和设计. Common.php文件定义了一系列的全局函数(一般来说,全局函数具有最高的加载优先权,因此大多数的框架中BootStrap ...
- CI框架源码阅读笔记2 一切的入口 index.php
上一节(CI框架源码阅读笔记1 - 环境准备.基本术语和框架流程)中,我们提到了CI框架的基本流程,这里再次贴出流程图,以备参考: 作为CI框架的入口文件,源码阅读,自然由此开始.在源码阅读的过程中, ...
- 源码阅读笔记 - 1 MSVC2015中的std::sort
大约寒假开始的时候我就已经把std::sort的源码阅读完毕并理解其中的做法了,到了寒假结尾,姑且把它写出来 这是我的第一篇源码阅读笔记,以后会发更多的,包括算法和库实现,源码会按照我自己的代码风格格 ...
- Three.js源码阅读笔记-5
Core::Ray 该类用来表示空间中的“射线”,主要用来进行碰撞检测. THREE.Ray = function ( origin, direction ) { this.origin = ( or ...
- PHP源码阅读笔记一(explode和implode函数分析)
PHP源码阅读笔记一一.explode和implode函数array explode ( string separator, string string [, int limit] )此函数返回由字符 ...
- AQS源码阅读笔记(一)
AQS源码阅读笔记 先看下这个类张非常重要的一个静态内部类Node.如下: static final class Node { //表示当前节点以共享模式等待锁 static final Node S ...
随机推荐
- Ubuntu 14.04 LTS 下使用源码编译安装 Sagemath 6.7 x64 (小结)
原先博客放弃使用,几篇文章搬运过来 下载源码包 系统的最低要求: 6GB 硬盘 : 2GB RAM. 命令行工具: A C/C++ compiler: Since Sage builds its ow ...
- yum-Remi源配置
Remi repository 是包含最新版本 PHP 和 MySQL 包的 Linux 源,由 Remi 提供维护. 有个这个源之后,使用 YUM 安装或更新 PHP.MySQL.phpMyAdmi ...
- python 使用多线程进行并发编程/互斥锁的使用
import threading import time """ python的thread模块是比较底层的模块,python的threading模块是对thread做了 ...
- Android:weight,margin,padding详解实例
weight详解 weight是用来等比例划分区域的属性. 案例代码 <LinearLayout xmlns:android="http://schemas.android.com/a ...
- 闲话ajax,例ajax轮询,ajax上传文件[开发篇]
引语:ajax这门技术早已见怪不怪了,我本人也只是就自己真实的经验去总结一些不足道的话.供不是特别了解的朋友参考参考! 本来早就想写一篇关于ajax的文章的,但是前段时间一直很忙,就搁置了,趁着元旦放 ...
- iOS开发笔记(Swift)-针对Swift调用PPiFlatSegmentedControl项目的一些修改
PPiFlatSegmentedControl项目是一个很流行的开源iOS控件库,提供了扁平化风格(Flat style)的SegmentedControl,可以自定义segment的颜色,图标.大小 ...
- 为什么我们喜欢用 sigmoid 这类 S 型非线性变换?
本文整理自 @老师木 的一条图片新浪微博,从另一个角度给出为何采用 sigmoid 函数作非线性变换的解释. 为什么我们喜欢用 sigmoid 这类 S 型非线性变换?
- MLlib之NaiveBayes算法源码学习
package org.apache.spark.mllib.classification import breeze.linalg.{DenseMatrix => BDM, DenseVect ...
- 解决vue路由history模式刷新后404的问题
server { listen ;#默认端口是80,如果端口没被占用可以不用修改 server_name localhost; root E:/vue/my_project/dist;#vue项目的打 ...
- ConfigUtil读取配置文件工具类
ConfigUtil package com.sso.util; import java.io.FileNotFoundException; import java.io.IOException; i ...