基于ZooKeeper,Spring设计实现的参数系统

简介

基于ZooKeeper服务端、ZooKeeper Java客户端以及Spring框架设计的用于系统内部进行参数维护的系统。


设计背景

在我们日常开发的系统内部,开发过程中最常见的一项工作便是常用参数的维护,从我学习Java以来,参数的配置多样化,最常见的方式是properties配置文件或者是xml配置文件,高深点的用法是JMX MBean进行参数管理以及数据库参数配置。我们对现有的参数配置方式进行分析,详见下表:

基于上述各类参数配置分析,一番思考设想,设计出如下结构的[参数中心系统](详细设计链接),设计说明查看下一节:


系统设计说明

参数中心系统,顾名思义,主要是将参数集中化,在实际开发中,一个业务的实现需要几个甚至数十个模块联合完成,每个模块都需要进行参数的更新维护,一个模块的参数更新设计缺陷,在进行参数维护时,就可能导致某个业务的中断,故需要将多参数管理统一化管理;统一化的参数管理方式,便可能涉及到了参数数据的统一存储,统一之后便出现了性能瓶颈需求,不然所有鸡蛋装一个篮子里,一出问题全部碎掉;在集中化后,各个模块有自己的参数,有些参数可能仅限单个系统访问,便需要安全的参数访问方式;在参数使用过程中,常见的功能之一便是参数的实时维护;在项目投产过程中,经常因为参数配置问题比如配置错误等情况导致业务中断,故需要一个参数检查表来确认参数的正确性;参数管理整合后,需要方便的操作来实现管理功能。概括一下,参数中心系统需要满足以下技术需求:

  • 多系统、多模式、安全、动态维护的参数配置
  • 个性化话参数配置(普通字符窜,JSON字符窜,数组窜)
  • 低侵入
  • 快捷的参数导入导出功能
  • 便捷的管理方式
  • 上线参数检查表,用于上线时各类参数的检查,防止出错
  • 高可用
  • 安全控制

根据上述分析,设计之初,思考如何实现多系统多模式的参数存储,虽然一直知道ZooKeeper这个东西,但从未详细了解过,偶然机会大致学习了一下ZooKeeper,发现ZooKeeper的各类机制与参数中心系统设计相吻合,比如:多系统多模式的参数存储与ZooKeeper的目录型存储方式相似,查看下面图3-1展示;参数的安全方式认证与ZooKeeper的ACL机制吻合;参数实时维护可以借鉴ZooKeeper的Watcher机制;参数中心系统的高性能高可用设计与ZooKeeper的集群方式相吻合。这样下来,参数中心系统最大的问题参数存储模块服务端得到了完美的解决。接下来的便是基于ZooKeeper设计出对应的客户端,管理端。

图3-1 基于ZooKeeper的参数存储

Java应用端常用的技术之一便是Spring框架,也符合低侵入的设计原则,在使用Spring开发过程中,常用的功能之一便是使用${}引用properties配置文件内的参数,如此方便的参数配置方式,我决定使用类似的方式,配置方式为zk{}(zk表示ZooKeeper参数),故客户端的设计是基于Spring的设计。


系统技术组合

ZooKeeper集群 + ZooKeeper Java客户端 + Spring BeanFactoryPostProcessor扩展点 + JSON字符窜解析 + Spring SpEL表达式


设计实现(重点)

根据上述设计说明等信息,最后得出这样一个系统,基于ZooKeeper参数存储,Spring客户端使用zk{}进行参数配置的参数中心系统。

  • 服务端

服务端设计如3-1图所示(在实际开发过程中可能稍有变动)

  • 客户端(重点)

在进行参数中心系统客户端实现之前,我们先了解一点Spring框架的基础知识。

在Spring框架开发过程中,最常用的配置是<bean/>标签的使用,在工作中,最常听的一种说法是,在xml里配置上就可以使用bean了,就有对象了,这种理解潜在一层含义xml直接配置成了java bean,而实际上,Spring中bean的定义最终表现为BeanDefinition对象,个人理解为xml实际配置的是bean的说明信息,Spring将这些说明信息转换为了BeanDefinition对象,再由BeanDefinition生成了我们最终看到的bean,实际流程为[xml配置->BeanDefinition->Bean]而一般开发者不知道BeanDefinition,故理解含义成了[xml配置->Bean],中间缺少了重要的环节。在BeanDefinition到Bean这个过程中,Spring由BeanFactory生成实际的bean,在实际bean产生前,Spring提供了BeanFactoryPostProcessor扩展点(类似还有BeanPostProcessor),通过该扩展点可以获取到配置的BeanDefinition信息,用于自定义扩展对bean定义变更修改,实现自由控制。

Spring允许开发者实现自定义的扩展点,实现特定的接口,使用通用的配置即可注册一个扩展点到Spring容器内。详细学习参考https://docs.spring.io/spring/docs/4.3.19.RELEASE/spring-framework-reference/htmlsingle/#beans-factory-nature。

参数中心系统参数的配置实现参考了Spring的${}参数配置,我们对${}的实现做简单学习。${}的实现便使用了Spring扩展点BeanFactoryPostProcessor,开发中常见配置如下:

上图中采用了context:property-placeholder标签配置,根据Spring context的xsd说明文件,我们知道了property-placeholder对应的实际类为org.springframework.context.support.PropertySourcesPlaceholderConfigurer,context:property-placeholder配置实际为在spring容器内注册一个扩展点,实现${}表达式的解析。实现类图以及调用流程大致如下,再详细过程查看源码,(有句话叫做师傅领进门,修行在个人):

参数中心系统客户端的实现代码与上述实现类似,不同的是properties配置文件变成了ZooKeeper参数存储,${}变成了zk{}。

客户端项目名称:itwatertop-pczk-client

  • 管理端

基于H5的管理页面设计,详细情况还未设想(先实现了主要的服务端客户端,管理端暂时可以使用ZooKeeper的客户端)。


客户端设计源码

客户端程序结构如下:

文件说明:

  • BaseLoader.java 数据加载基类
  • ZookeeperDataLoader.java Java ZooKeeper客户端实现数据加载,参数更新回调。
  • PlaceholderMsg.java zk{zkexp} zk配置表达式解析结果,以及使用该表达式的bean属性获取SpEL表达式。
  • ParamCenterStore.java 对ZooKeeper参数服务端获取的参数信息做缓存,并且将对应的使用该参数的Bean属性表达式统计,方便ZooKeeper参数变更时回调使用。
  • PczkConstants.java 系统内常量字符窜整合。
  • PczkStringValueResolver.java 表达式解析统一接口
  • PczkPropertyPlaceholderConfiguer.java 实现Spring扩展点BeanFactoryPostProcessor,通过该扩展点对BeanDefinition配置元信息做解析以及变更。
  • PropertyPlaceholderHelper.java 具体实现zk{}表达式解析规则。
  • PczkBeanDefinitionVisitor.java 对Spring IoC容器内的BeanDefinition属性配置信息做解析,主要结合PczkPropertyPlaceholderConfiguer.java使用。
  • test目录下包含一部分测试代码,可以自行查看

客户端代码实现简介:

根据上述需求,客户端代码需要具备的能力包括:

  1. 与ZooKeeper服务器的连通,并获取参数信息
  2. Spring xml中zk{}表达式的解析
  3. 多样化的参数配置,支持字符窜,对象,数组
  4. ZooKeeper参数变更回调,维护参数信息

针对上面4种要求,在开发时使用以下解决办法:

  1. 使用ZooKeeper Java客户端;
  2. 结合Spring的扩展点BeanFactoryPostProcessor;
  3. 在ZooKeeper服务端节点内设置数据时设置字符窜/JSON对象字符窜或者是JSON数组字符窜,客户端使用数据时分别配置为zk{param},zk{param.key},zk{param[i]},通过对zk{}表达式解析判断ZooKeeper参数格式,若为JSON字符窜使用FastJSON对字符窜做解析,访问对应属性值;
  4. 针对参数变更回调,在解析zk{}表达式时拼接出了可以访问到对应bean属性的SpEL表达式,通过SpEL表达式访问bean属性调用setter方法,因此属性操作也受到SpEL表达式的限制。在个别情况下,由于参数的变更可能需要别的一下操作处理,比如重新建立连接,这个可以自行扩展代码,比如比较上一次的值和当前值是否一致,不一致做出新的操作(现在也在设想怎么可以自动识别进行额外操作)。

客户端详细实现源码下载:访问GitHub项目(注释还是比较清晰的)


说明

本人技术有限,上述有错误的理解欢迎指出,共同交流学习,若对上述说明不了解,建议先学习一点Spring IoC设计,学习地址:https://docs.spring.io/spring/docs/4.3.19.RELEASE/spring-framework-reference/htmlsingle,若对于客户端的设计有好的建议可以提出来,共同讨论。

原文发布于微信公众号 - JAVA烂猪皮(gp1106701116)

原文发表时间:2018-09-26

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏FreeBuf

Linux Rootkit系列一:LKM的基础编写及隐藏

免责声明:本文介绍的安全知识方法以及代码仅用于渗透测试及安全教学使用,禁止任何非法用途,后果自负 前言:作者最近在学习有关linux rootkit的原理与防范...

32710
来自专栏微服务生态

性能分析系列-小命令保证大性能

最近在工作中经常和性能压测工作打交道,积累了一些性能分析经验,我觉得这些经验对每一个开发者都有帮助的,能开发出性能高的代码也是我们的最终目标。

975
来自专栏开发之途

Android IPC机制(1)-序列化机制

1455
来自专栏张善友的专栏

Compass: 在你的应用中集成搜索功能

驱动力 在许多应用程序中,用户总会提出搜索和查询领域实例的需求。他们或者希望构建一个进入应用程序的入口或者希望填充表单的机制。非常典型的解决方案是用浏览的方式(...

2039
来自专栏芋道源码1024

Java中高级面试题(4)

这里选了几道高频面试题以及一些解答。不一定全部正确,有一些是没有固定答案的,如果发现有错误的欢迎纠正,如果有更好的回答,热烈欢迎留言探讨。

1700
来自专栏Jackson0714

PHP内核之旅-1.生命周期

3306
来自专栏三丰SanFeng

Apache thrift - 使用,内部实现及构建一个可扩展的RPC框架

本文首先介绍了什么是Apache Thrift,接着介绍了Thrift的安装部署及如何利用Thrift来实现一个简单的RPC应用,并简单的探究了一下Thrift...

6459
来自专栏大内老A

《Enterprise Library深入解析与灵活应用》博文系列汇总

Enterprise Library是微软P&P部门开发的众多Open source框架中的一个,最新的版本已经出到了4.1。由于接触Enterprise Li...

1837
来自专栏walterlv - 吕毅的博客

如何在 MSBuild Target(Exec)中报告编译错误和编译警告

发布于 2018-06-20 05:17 更新于 2018-07...

602
来自专栏java思维导图

Java中高级面试题部分答案解析(4)

这里选了几道高频面试题以及一些解答。不一定全部正确,有一些是没有固定答案的,如果发现有错误的欢迎纠正,如果有更好的回答,热烈欢迎留言探讨。

1233

扫码关注云+社区