前言

之前聊了客户端的一些功能,例如融入 Spring, @value 注解的自动刷新实现,长轮询等,这次从客户端的整体设计来聊聊。

设计

上图是 client 项目的包结构。

其中,核心包就是 internals 包,包含了客户端的主要功能逻辑。主要有以下功能:

  1. 获取 ConfigService 服务的远程配置。
  2. 长轮询/定时轮询 ConfigService。
  3. 监听机制——更新后,立即通知应用程序。
  4. 兼容 Spring 各个版本(这个是在 spring 包中,但我认为也算重要功能 ^_^)。
首先说第一个功能:获取 ConfigService 服务的远程配置

实现此功能的类为:RemoteConfigRepository。该类有以下几个重要的方法:

  1. 构造方法:该方法里包含了很多初始化的过程,虽然我觉得应该放在 init 之类的方法中
  2. getConfig() 根据 namespace 获取配置
  3. onLongPollNotified() 当收到长连接通知时触发响应
  4. addChangeListener() 添加监听器
  5. removeChangeListener() 删除监听器

注意:setUpstreamRepository 是空的。看注释,是个 fallback 设计。

其中,getConfig 方法是获取这个 namespace 的配置,返回的是 Properties 对象(就是个 Map)。然后,从这个对象中取出对应的值,就 ok 了。

第二个功能:长轮询/定时轮询 ConfigService。

这个功能的主要实现类是:RemoteConfigLongPollService。

该类主要的方法有 2 个,构造方法和 submit 方法。注意,这个类是单例的(由 google 的 inject 实现)。
构造方法中,做了很多的初始化工作。而 submit 方法则是开启长轮询,轮询的方式是:携带 AppId 去请求 ConfigServcie,得到所有的 namespace 更新通知,然后通知对应的 RemoteConfigRepository 去请求真正的数据。大概的设计如下图:

每一个 namespace 在一个应用中,都对应一个 RemoteConfigRepository,所有的 RemoteConfigRepository 都归属 RemoteConfigLongPollService 长轮询服务管理,当长轮询得到通知,便通知对应的 RemoteConfigRepository 进行服务请求以便执行更新本地缓存和通知监听器操作。

通知,作为 fallback 方案—— 定时轮询也充当了长轮询失效的最后屏障。

第三个功能:监听机制——更新后,立即通知应用程序。

从上图可以看出,轮询之后,如果有更新响应,则立即通知 RemoteConfigRepository,然后,RemoteConfigRepository 再次从配置中心拉取配置,从而更新本地 Config 对象的内容。

更新完毕后,则通知 Config 的“配置变化监听器”。也就是 ConfigChangeListener 的 onChange 方法。这个监听器是监听 Config 对象的。

实际上,每个 Config 对象在初始化的时候,都会往 RemoteConfigRepository 对象里添加一个监听器,实际上就是添加自己。

当 RemoteConfigRepository 发生变化的时候,触发 onRepositoryChange 方法,onRepositoryChange 又会触发 onChange 方法。大概的设计图就是下面这个样子:

上图中,紫色的 DefaultConfig 是核心,他依赖了 RemoteConfigRepository, 而 RemoteConfigRepository 反过来组合了他,同时 DefaultConfig 也聚合了用户实现的监听器 ConfigChangeListener 的子类。

那么,当远程 Repository 变化的时候,就可以通知 Client 的缓存 Config 对象,而 Config 缓存对象变化的时候,就可以通知用户的程序(监听器)。实现整体的监听机制。

总的来说,就是通过两层监听机制来实现的。其中 DefaultConfig 实现了两个角色,既是观察者,也是被观察者。

第四个功能:兼容 Spring 各个版本

首先,如果没有这个功能,Apollo 也会能够正常运行的,不过,你只能使用 API 的方式,不能使用注解,标签等 Spring 应用熟悉的方式。

如果想用 Spring 的方式使用 Apollo ,那么就得遵守 Spring 的约定,实现 Spring 的接口,将自己融入到 Spring 中。

其中,主要解决的问题就是,如何在 Spring 初始化的时候,Apollo 也初始化?这点我们在之前的文章中说了,也就是 Spring 的 3 个入口。在这些入口里初始化。

另外,将配置放置到 Spring 的环境中,也是一个工作,因为,如果不放到环境中,Spring 初始时需要的那些参数就无法取到了。

所以,要将 Config 对象包装成 Spring 熟悉的 ConfigPropertySource 对象,算是一个适配器模式吧。

在初始化配置的时候,会从远程配置中心拿到配置,包装成 ConfigPropertySource 对象,再利用 CompositePropertySource 组合属性配置(多个 namespace)聚合所有 Config 对象。

CompositePropertySource 最后会添加到 ConfigurableEnvironment 环境对象中,spring 就可以从这个对象 中取出配置进行初始化。

并且,在 SpringBoot 环境下,Apollo 可以优先加载指定的配置,这些配置在 SpringContext 容器初始化的时候就开始被注入到环境中,这样就可以将一些系统初始化的配置也放到配置中心了,尽量让本地少一点配置。这个功能的启用需要参数:apollo.bootstrap.enabled=true,配置的namespace 则是 apollo.bootstrap.namespaces = XXX

并且,该配置的优先级是最高的,Apollo 将这个配置放在了 Spring 环境对象中的第一个位置,当循环获取配置的时候,优先获取这个配置。

总结

好了,关于 Apollo 客户端的设计,大概就是这些,总体来讲比较简单, 4 个功能:

  1. 获取远程配置
  2. 长轮询/定时轮询
  3. 配置更新监听机制。
  4. 兼容 Spring。

抛出一个问题:

Apollo 似乎没有给用户留扩展接口?如果能像 Spring,Mybatis 一样,留一个或者多个切面给用户,让用户能够在加载配置的时候,做一些事情啥的,或许更好。

Apollo 4 客户端 SDK 设计的更多相关文章

  1. 客户端SDK测试思路

    本文来自网易云社区 作者:万春艳 是什么 客户端SDK是为第三方开发者提供的软件开发工具包,包括SDK接口.开发文档和Demo示例等.SDK和应用之间是什么关系呢?以云信即时消息服务为例,如下图所示, ...

  2. 猿题库 iOS 客户端架构设计(原文地址:http://gracelancy.com/blog/2016/01/06/ape-ios-arch-design/)

    猿题库 iOS 客户端架构设计 序 猿题库是一个拥有数千万用户的创业公司,从2013年题库项目起步到2015年,团队保持了极高的生产效率,使我们的产品完成了五个大版本和数十个小版本的高速迭代.在如此快 ...

  3. 基于Hadoop开发网络云盘系统客户端界面设计初稿

    基于Hadoop开发网络云盘系统客户端界面设计初稿 前言: 本文是<基于Hadoop开发网络云盘系统架构设计方案>的第二篇,针对界面原型原本考虑有两个方案:1.类windows模式,文件夹 ...

  4. 网易考拉Android客户端网络模块设计

    本文来自网易云社区 作者:王鲁才 客户端开发中不可避免的需要接触到访问网络的需求,如何把访问网络模块设计的更具有扩展性是每一个移动开发者不得不面对的事情.现在有很多主流的网络请求处理框架,如Squar ...

  5. 猿题库 iOS 客户端架构设计

    原文: http://mp.weixin.qq.com/s?__biz=MjM5NTIyNTUyMQ==&mid=444322139&idx=1&sn=c7bef4d439f4 ...

  6. 猿题库 iOS 客户端架构设计-唐巧

    序 猿题库是一个拥有数千万用户的创业公司,从20013年题库项目起步到2015年,团队保持了极高的生产效率,使我们的产品完成了五个大版本和数十个小版本的高速迭代. 在如此快速的开发过程中,如何保证代码 ...

  7. 直播时代--IOS直播客户端SDK,美颜直播【开源】

    当前视频直播非常火爆,手机端的视频直播也非常火爆,PGC.UGC的视频直播门槛都降低了很多. 本文介绍一个:IOS 客户端直播的SDK,代码完全开源. 直播时代:让IOS普通开发者一天内做出一个RTM ...

  8. 无线客户端框架设计(5.1):将JSON映射为实体对象(iOS篇)

    iOS开发人员已经习惯于将JSON转换为字典或者数组来进行操作了,接下来我要做的事情,可能匪夷所思,但是,对WP和Android开发人员而言,他们更倾向于将JSON转换为实体对象进行操作. 我所设计的 ...

  9. 直播时代--IOS直播客户端SDK,美艳直播【开源】

    看到该文章我非常喜欢,为了方便自己查看和参考所以将其复制过来,源文地址:http://www.cnblogs.com/runner42/p/5241407.html 请支持原作者.原作者如看到请原谅复 ...

随机推荐

  1. Json中对日期的处理

    前言:Json对日期的处理很特别,我们不能简单的转换而得到我们想要的结果,需要进行特殊处理 一.JSon序列化和反序列化对日期的处理 JsonHelper类: using System.IO; usi ...

  2. @RemoteProxy()注释 与@File注释的使用

    @RemoteProxy()注释 dwr3.0可以通过全注解的方式,极大的简化了配置,所有xml配置加在一起不超过20行,而且使用更加简单,bean注入的问题也都解决.配置步骤如下: web.xml的 ...

  3. 下拉列表 通过option 改变div的内容

    <!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>& ...

  4. spring-boot json数据交互

    SpringBoot学习之Json数据交互 最近在弄监控主机项目,对javaweb又再努力学习.实际的项目场景中,前后分离几乎是所以项目的标配,全栈的时代的逐渐远去,后端负责业务逻辑处理,前端负责数据 ...

  5. springboot 初始化 web 项目 启动报错。。。一直解决不了

    1. 一个简单的SpringBoot项目,启动时报错信息: ERROR 18688 --- [cat-startStop-1] org.apache.catalina.core.ContainerBa ...

  6. ActiveMQ_2安装

    Linux安装 环境JDK7以上 gz文件拷贝到 /usr/local/目录下 解压 后缀为 .tar.gz的压缩包 进入解压后的文件夹 cd apache-activemq-x.xx.x/ cd b ...

  7. Acegi框架

    Acegi(Acegi Security)框架,是一个能为基于Spring的企业应用提供强大而灵活安全访问控制解决方案的框架,Acegi已经成为 Spring官方的一个子项目,所以也称为Spring ...

  8. uniGUI动态建立Form及释放

    uniGUI动态建立Form及释放 (2015-10-01 14:51:12) 转载▼   分类: uniGUI 用uniGUI开发的项目中,难免要遇到动态建立一个Form,再释放掉,与传统Delph ...

  9. ESB结合门户Portlet实现数据分析

    1 背景概述 笔者在公司做集成项目时,通常会涉及ESB与Portal结合实现图表数据分析功能.通过ESB获取数据库信息,然后在门户上采用Portlet接收ESB中的数据URL最后展现到门户上.本文为项 ...

  10. Android开发工程师文集-相关控件的讲解,五大布局

    前言 大家好,给大家带来Android开发工程师文集-相关控件的讲解,五大布局的概述,希望你们喜欢 TextView控件 TextView控件有哪些属性: android:id->控件的id a ...