基于ZooKeeper,Spring设计实现的参数系统
一、简介
基于ZooKeeper服务端、ZooKeeper Java客户端以及Spring框架设计的用于系统内部进行参数维护的系统。
二、设计背景
在我们日常开发的系统内部,开发过程中最常见的一项工作便是常用参数的维护,从我学习Java以来,参数的配置多样化,最常见的方式是properties配置文件或者是xml配置文件,高深点的用法是JMX MBean进行参数管理以及数据库参数配置。我们对现有的参数配置方式进行分析,详见下表:
配置方式 | 常见问题 | 备注 |
---|---|---|
代码内字符窜字面量配置 | 每次参数的修改都需要重新编译 | |
properties配置文件/xml配置文件 | 普通用法虽然将参数从代码内抽离出来,但是无法随时更新生效 | Spring提供的ReloadableResourceBundleMessageSource工具类可以实现热加载Properties文件,将参数配置文件从代码分离可以做到不停机不重启做参数维护,并被程序加载,但是仍需系统重新从文件资源内获取新的参数值 |
JMX参数配置 | 标准MBEAN是有侵入性的,他要管理的对象是符合JAVA BEAN规范的对象。但是要作为标准MBEAN而被管理,就需要实现一个接口。这个接口的名称必须是类名加上MBean。 | Spring支持将普通Bean通过配置MBeanExporter生成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目录下包含一部分测试代码,可以自行查看
客户端代码实现简介:
根据上述需求,客户端代码需要具备的能力包括:
- 与ZooKeeper服务器的连通,并获取参数信息
- Spring xml中zk{}表达式的解析
- 多样化的参数配置,支持字符窜,对象,数组
- ZooKeeper参数变更回调,维护参数信息
针对上面4种要求,在开发时使用以下解决办法:
- 使用ZooKeeper Java客户端;
- 结合Spring的扩展点BeanFactoryPostProcessor;
- 在ZooKeeper服务端节点内设置数据时设置字符窜/JSON对象字符窜或者是JSON数组字符窜,客户端使用数据时分别配置为zk{param},zk{param.key},zk{param[i]},通过对zk{}表达式解析判断ZooKeeper参数格式,若为JSON字符窜使用FastJSON对字符窜做解析,访问对应属性值;
- 针对参数变更回调,在解析zk{}表达式时拼接出了可以访问到对应bean属性的SpEL表达式,通过SpEL表达式访问bean属性调用setter方法,因此属性操作也受到SpEL表达式的限制。在个别情况下,由于参数的变更可能需要别的一下操作处理,比如重新建立连接,这个可以自行扩展代码,比如比较上一次的值和当前值是否一致,不一致做出新的操作(现在也在设想怎么可以自动识别进行额外操作)。
客户端详细实现源码下载:访问GitHub项目(注释还是比较清晰的)
七、说明
本人技术有限,上述有错误的理解欢迎指出,共同交流学习,若对上述说明不了解,建议先学习一点Spring IoC设计,学习地址:https://docs.spring.io/spring/docs/4.3.19.RELEASE/spring-framework-reference/htmlsingle,若对于客户端的设计有好的建议可以提出来,共同讨论。
基于ZooKeeper,Spring设计实现的参数系统的更多相关文章
- 日志系统之基于Zookeeper的分布式协同设计
近期这段时间在设计和实现日志系统.在整个日志系统系统中Zookeeper的作用非常重要--它用于协调各个分布式组件并提供必要的配置信息和元数据.这篇文章主要分享一下Zookeeper的使用场景. 这里 ...
- 基于Spring设计并实现RESTful Web Services(转)
基于Spring设计并实现RESTful Web Services 在本教程中,你将会使用Spring来创建一个具有生产力的RESTful网络服务. 为什么用RESTful网络服务? 从和Amazon ...
- 基于B/S架构的在线考试系统的设计与实现
前言 这个是我的Web课程设计,用到的主要是JSP技术并使用了大量JSTL标签,所有代码已经上传到了我的Github仓库里,地址:https://github.com/quanbisen/online ...
- 基于STM32+华为云IOT设计智能称重系统
摘要:选择部署多个重量传感器和必要的算法.通过WiFi 通信模块.GPS定位模块,采集车辆称重数据一地理位置信息,并通过网络发送至云平台,设计图形化UI界面展示称重.地图位置等重要信息,实现对称重系统 ...
- 《Spring_Four》第三次作业——基于Jsoup的大学生考试信息展示系统的原型设计与开发
<Spring_Four团队>第三次团队项目——基于Jsoup的大学生考试信息展示系统的原型设计与开发 一.实验目的与要求 (1)掌握软件原型开发技术: (2)学习使用软件原型开发工具:本 ...
- 基于zookeeper实现分布式配置中心(二)
上一篇(基于zookeeper实现分布式配置中心(一))讲述了zookeeper相关概念和工作原理.接下来根据zookeeper的特性,简单实现一个分布式配置中心. 配置中心的优势 1.各环境配置集中 ...
- ShardingJdbc基于Zookeeper实现分布式治理
随着数据规模的不断膨胀,使用多节点集群的分布式方式逐渐成为趋势.在这种情况下,如何高效.自动化管理集群节点,实现不同节点的协同工作,配置一致性,状态一致性,高可用性,可观测性等,就成为一个重要的挑战. ...
- 基于ZooKeeper的分布式Session实现(转)
1. 认识ZooKeeper ZooKeeper—— “动物园管理员”.动物园里当然有好多的动物,游客可以根据动物园提供的向导图到不同的场馆观赏各种类型的动物,而不是像走在原始丛林里,心惊胆颤的被 ...
- 基于ZooKeeper的分布式Session实现
1. 认识ZooKeeper ZooKeeper—— “动物园管理员”.动物园里当然有好多的动物,游客可以根据动物园提供的向导图到不同的场馆观赏各种类型的动物,而不是像走在原始丛林里,心惊胆颤的被 ...
随机推荐
- Linux中增加组和用户
新服务器增加用户: 1.创建一个新的组, groupadd oracle 2.useradd 命令用于建立用户账号(-g 指定用户所属的群组) useradd -g oracle oracle 3.再 ...
- Go与接口:接口即约定
接口 接口类型是对其他类型行为的概括与抽象.我们可以通过接口来约定某一类通用行为.Go语言的接口是隐式的:只要实现接口A的所有方法就代表实现了接口A. 接口即约定 接口是什么样的? package i ...
- Spring Boot +Vue 项目实战笔记(二):前后端结合测试(登录页面开发)
前言:关于开发环境 每位 Coder 都有自己偏好的开发工具,从大的方面划分主要有文本编辑器流和 IDE 流两种,我有一段时间也喜欢用编辑器(Sublime Text.Vim),但对我来说开发效率确实 ...
- 三大操作系统对比使用之·MacOSX
时间:2018-11-13 整理:byzqy 本篇是一篇个人对Mac系统使用习惯和应用推荐的分享,在此记录,以便后续使用查询! 打开终端: command+空格,调出"聚焦搜索(Spotli ...
- 【SpringMVC】RESTFul简介以及案例实现
RESTful 概念 REST:Representational State Transfer,表现层资源状态转移. 资源 资源是一种看待服务器的方式,即,将服务器看作是由很多离散的资源组成.每个资源 ...
- CSS布局中最小高度的妙用
CSS布局中最小高度的妙用 --最小高度可以设定一个BOX的最小高度,当其内容较少时时,也能保持BOX的高度为一定,超出就自动向下延伸最小高度可以设定一个BOX的最小高度,当其内容较少时时,也能保持B ...
- shell脚本 批量添加删除用户
2021-07-26 1.批量添加用户 # 编写脚本 vi add_student_50.sh # 添加用户组 student groupadd student # 添加用户 student1-stu ...
- Servlet监听器详解及举例
监听器就是一个实现特定接口的普通java程序,这个程序专门用于监听另一个java对象的方法调用或属性改变,当被监听对象发生上述事件后,监听器某个方法将立即被执行. 监听器原理 监听原理 1.存在事件源 ...
- MySQL版本浅介
一.关于MySQL发行版介绍: 1. MySQL官方发行版 MySQL是最流行的数据库,主要特点: 简单:MySQL使用很简单,可以无师自通地参照文档安装运行和使用MySQL,几乎没有什么门槛. 开源 ...
- Django的form组件——ModelForm实战
模型: from django.db import models class Book(models.Model): book_name = models.CharField(max_length=3 ...