「造个轮子」——cicada 设计一个配置模块

前言
在前两次的 cicada 版本中其实还不支持读取配置文件,比如对端口、路由的配置。
因此我按照自己的想法创建了一个 issue ,也收集到了一些很不错的建议。


最终其实还是按照我之前的想法来做了这个配置管理。
同时将
cicada升级到了v1.0.2。
目标
在做之前是要把需求想好,到底怎样的一个配置管理是对开发人员来说比较友好的?
我认为有以下几点:
- 可以自定义配置,并且支持不同的环境(开发、测试、生产)。
- 使用灵活。对使用者来说不要有太多的束缚。
理论上来说配置这个东西应当完全独立出来,由一个配置中心来负责管理并且这样可以与应用解耦。
不过这样的实现和当前 cicada 的定义有些冲突,我想尽量小的依赖第三方组件并可以完全独立运行。
因此基于这样的情况便有了以下的实现。
使用
在看实现之前先看看基于目前的配置管理如何在业务中使用起来。
结合现在大家使用 SpringBoot 的习惯,cicada 默认会读取 classpath 下的 application.properties 配置文件。并且会默认读取其中的应用端口以及初始路由地址。
同时也新增了一个 api。
public class MainStart {
public static void main(String[] args) throws Exception {
CicadaServer.start(MainStart.class,"/cicada-example") ;
}
}
public class MainStart {
public static void main(String[] args) throws Exception {
CicadaServer.start(MainStart.class) ;
}
}
这样在不传默认地址的时候 cicada 会从 application.properties 中读取。
考虑到后面可维护的情况,cicada 也支持配置各种不同的配置文件。
使用也比较简单,只需要继承 cicada 提供的一个抽象类即可。
public class KafkaConfiguration extends AbstractCicadaConfiguration {
public KafkaConfiguration() {
super.setPropertiesName("kafka.properties");
}
}
public class RedisConfiguration extends AbstractCicadaConfiguration {
public RedisConfiguration() {
super.setPropertiesName("redis.properties");
}
}

按照这样的配置也会默认从 classpath 读取这两个配置文件。
当然这里有个前提:代码里配置的文件名必须得和配置文件名称相同。
那如何在业务中读取这两个配置文件的内容呢?
这也简单,代码一看就懂:

- 首先需要通过
ConfigurationHolder获取各自不同配置的管理对象(需要显式指定类类型)。 - 通过
get()方法直接获取配置。 - 同时也支持获取
application.properties里的配置。
同时为了支持在不同环境的使用,当配置了启动参数将会优先读取。
-Dapplication.properties=/xx/application.properties
-Dkafka.properties=/xx/kakfa.properties
-Dredis.properties=/xx/redis.properties
这样算是基本实现了上述的配置要求。
实现
要实现以上的功能有几个核心点:
- 加载所有配置文件。
- 将不同的配置文件用不同的对象进行管理。
- 提供简易的接口使用。
由于 cicada 需要支持多个配置文件,所有需要定义一个抽象类供所有的配置管理实现。

定义比较简单,其中有两个重要的成员变量:
- 文件名称:用于初始化时通过名称加载配置文件。
Properties其实就是一个 Map 结构的缓存,用于存放所有的配置。当然对外提供的查询是基于它的。
接着就是在初始化时需要找出所有继承了 AbstractCicadaConfiguration 的类。

查询出来之后自然是要进行遍历同时反射创建对象。
由于之前已经调用了
super.setPropertiesName("redis.properties");
来赋值配置文件名称,所以还需要在遍历过程中将 Properties 进行赋值。
同时在这里也体现出优先读取的是 VM 启动参数中的配置文件。
String systemProperty = System.getProperty(conf.getPropertiesName());

需要额外提一点的是:在查找所有用户自定义的配置管理类时需要手动将 cicada 内置的
ApplicationConfiguration 加入其中。
因为使用应用的包名通过反射是查询不出该类的。
保存自定义配置管理
为了方便用户在使用时候可以随意的读取各个配置文件,所以还需要将反射创建的对象保存到一个内部缓存中,核心代码就是上上图中的这段代码:
// add configuration cache
ConfigurationHolder.addConfiguration(aClass.getName(), conf);
其中 ConfigurationHolder 的定义如下。

其实也是利用一个 Map 来存放这些对象。
这样在使用时候只需要取出即可。
KafkaConfiguration configuration = (KafkaConfiguration) getConfiguration(KafkaConfiguration.class);
String brokerList = configuration.get("kafka.broker.list");
重构
本次升级同时还重构了部分代码,比如启动类。
现在看上去要清爽和直接的多:

其中也有一点需要注意的地方。
大家如果查看日志的话会发现应用启动之后会打印本次的耗时,自然就是在启动时候记录一个时间,初始化完毕之后记录一个即可。

在之前的实现中由于都是在一个方法内,所以直接使用就行了。
但现在优化之后跨越了不同的方法和类,难道要把时间作为参数在各个方法之前传递嘛?
那未免太不优雅了。
所以 ThreadLocal 就有了发挥余地。
在初始化的方法中我将当前时间写入:
ThreadLocalHolder.setLocalTime(System.currentTimeMillis());
在最后记录日志的地方直接取出比较即可:

这样使用起来就完全不需要管什么参数传递了。
同时 ThreadLocalHolder 的定义:

这里还是有一点需要注意,在这种长生命周期的容器中一定得要记得及时清除。
我这里的时间在查询一次之后就不用了,所以完全放心的在 getLocalTime() 方法中删掉。
总结
这就是本次 v1.0.2 中的升级内容,包含了配置支持以及代码重构。其中有些内容我觉得对接触少的同学来说还是挺有帮助的。
关于上两次的版本介绍请查看这里:
还没点关注的朋友可以点波关注:
https://github.com/TogetherOS/cicada
也欢迎大家参与一起维护!。
同时后续关于 cicada 的更新会放慢一些。会介绍一些平时实战相关的内容,比如 Kafka 之类的,请持续关注。
你的点赞与转发是最大的支持。
「造个轮子」——cicada 设计一个配置模块的更多相关文章
- 「造个轮子」——cicada 源码分析
前言 两天前写了文章<「造个轮子」--cicada(轻量级 WEB 框架)> 向大家介绍了 cicada 之后收到很多反馈,也有许多不错的建议. 同时在 GitHub 也收获了 80 几颗 ...
- 「造个轮子」——cicada(轻量级 WEB 框架)
前言 俗话说 「不要重复造轮子」,关于是否有必要不再本次讨论范围. 创建这个项目的主要目的还是提升自己,看看和知名类开源项目的差距以及学习优秀的开源方式. 好了,现在着重来谈谈 cicada 这个项目 ...
- 「造个轮子」——设计 HTTP 请求全局上下文
前言 本次 Cicada 已经更新到了 v1.0.3. 主要是解决了两个 issue,#9(Boss线程数好像设置有误 ) #8(怎么返回纯字符串内容不要JSON格式?). 所以本次的主要更新为: C ...
- 「Netty实战 02」手把手教你实现自己的第一个 Netty 应用!新手也能搞懂!
大家好,我是 「后端技术进阶」 作者,一个热爱技术的少年. 很多小伙伴搞不清楚为啥要学习 Netty ,今天这篇文章开始之前,简单说一下自己的看法: @ 目录 服务端 创建服务端 自定义服务端 Cha ...
- 【LOJ】#3036. 「JOISC 2019 Day3」指定城市
LOJ#3036. 「JOISC 2019 Day3」指定城市 一个点的可以dp出来 两个点也可以dp出来 后面的就是在两个点的情况下选一条最长的链加进去,用线段树维护即可 #include < ...
- 力扣Leetcode 1248. 统计「优美子数组」
统计「优美子数组」 给你一个整数数组 nums 和一个整数 k. 如果某个 连续 子数组中恰好有 k 个奇数数字,我们就认为这个子数组是「优美子数组」. 请返回这个数组中「优美子数组」的数目. 示例 ...
- 零元学Expression Design 4 - Chapter 3 看小光被包围了!!如何活用「Text On Path」设计效果
原文:零元学Expression Design 4 - Chapter 3 看小光被包围了!!如何活用「Text On Path」设计效果 本章将教大家如何活用「Text On Path」,做出文绕图 ...
- 迄今为止最硬核的「Java8时间系统」设计原理与使用方法
为了使本篇文章更容易让读者读懂,我特意写了上一篇<任何人都需要知道的「世界时间系统」构成原理,尤其开发人员>的科普文章.本文才是重点,绝对要读,走起! Java平台时间系统的设计方案 几乎 ...
- 教你用python搭建一个「生活常识解答」机器人
今天教大家如何用Python爬虫去搭建一个「生活常识解答」机器人. 思路:这个机器人主要是依托于"阿里达摩院发布的语言模型PLUG",通过爬虫的方式,发送post请求(提问),然后 ...
随机推荐
- jdk1.7更新visualvm插件
所有的插件全部更新到hithub上 https://visualvm.github.io/pluginscenters.html 然后,在根据不同的JDK版本选择不同的插件地址.更改VisualVM插 ...
- nginx学习.第一部分
1.nginx的版本发布历史 2015年支持thread pool提供stream四层反向代理支持reuseport特性,支持http v2协议.完全可以替代LVS 2016年支持动态模块 2.ngi ...
- Docker 学习3 Docker镜像管理基础
一.docker 常用操作及原理 1.docker 常用操作 2.docker 机制 1.docker client端是通过http或者https与server端通信的.个 2.docker 镜像可以 ...
- Linux-信号量与P,V操作
Linux-信号量与P,V操作 内容 使用信号量实现进程互斥 使用信号量及PV实现子进程读写同步 机理 Linux信号量集 Linux信号量作为IPC机制的一种,与其他通信方式类似,Linux也是通过 ...
- python3安装lxmlpipinstall安装失败解决办法
最近在学习python爬虫技术,lxml模块拥有很强大的获取元素功能,但是安装时总超时报错,如下解决办法 选择好python版本→注意pip版本→下载对应lxml.whl→键入对应的字符串→bingo ...
- C#代码总结02---使用泛型来获取Asp前台页面全部控件,并进行属性修改
该方法:主要用于对前台页面的不同类型(TextBox.DropDownList.等)或全部控件进行批量操作,用于批量修改其属性(如,Text.Enable). private void GetCont ...
- ISP PIPLINE (十五) AF
主流的AF: CDAF, PDAF, laser assist AF(这个只是辅助,在微距或者拍摄纹理不明显的场景下好用). AF的大致原理就是检测图像锐度或者等价于锐度的参数,推动马达实现合焦或者对 ...
- java简单框架设计
设计框架包可以作为一个工具给大家用,需要有完全不同设计思路给出来,不同于我们去做一个web服务.网站. 或者一个业务微服务,需要从原来使用视角转换成一个构建者视角. 框架或者工具,更多是框架来管理或者 ...
- win10系统盘分多大合适?
WIN10系统盘分多大合适,想必许多网友在装系统的时候都犹豫不觉吧,不过现在的硬盘基本上都是512G 1T的机械硬盘,固态硬盘基本都是128G以上,256G几乎成为标配,所以WIN10系统盘空间还是足 ...
- RSP小组——团队冲刺博客二
RSP小组--团队冲刺博客二 冲刺日期:2018年12月11日 前言 经过第一天的冲刺,我们开始了我们冲刺之路,但是不知为什么,我们的动力并不足,首先可能是我们前期对该项目的编制过程中,因为没有经验, ...