本文主要是介绍企业服务架构演进-走上造轮子之路,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
本篇是企业服务架构演进系列的第六篇,本篇我打算从另外一个角度去说一下企业服务架构演进的过程中我个人的一些积累。我从正式工作的第二年开始有造轮子的想法,然后从最简单最基础的方式去做,慢慢的可以做一些复杂的工具去提高开发效率,提高程序性能等。到19年我几乎每个季度都会寻找一个合适的场景用业余时间去做一些创新性的东西,这些创新虽然不是那么重要,但是对于企业发展来说,这样的方式正是企业竞争力的一种体现。
工具类
- DAOUtils工具类
我从16年底开始做电子合同系统,有些列表页面需要开发,比较特别的地方是这些列表页的显示查询条件慢慢增加到20+个,而整张表的字段大概40多个。在当时这个系统还没有集成spring,orm框架也是公司自研的DAO框架,支持直接写sql执行,代码里动态拼sql。于是整个daoimpl的查询sql都是下面这样的:
if(a!= null){sql.append(a)}
if(b!= null){sql.append(b)}
if(c!= 0){sql.append(c)}
这样的if语句大概有10+条,如果每个查询条件不加注释则几乎看不懂sql是怎么拼的,拼的什么字段。
另外一个问题就是我们的表里基本上都有create_time,create_user,update_time,update_user这样的字段,每个表几乎都有修改状态等更新操作,要更新操作人等。
因此我琢磨了下,自己写了一个DAOUtils工具类。上面第一个问题的解决方案如下:
在DAOUtils实现类中增加一个@ColName(name),这个注解用在dto上面,准确的说这个dto是querydto,根据业务列表的查询模型来定的,查询dto可以直接作为DAO接口中的参数传进去,name属性值就是查询表的查询字段。在执行sql之前先通过DAOUtils里面的方法动态生成where 后面的查询条件子句,然后再拼接上select from tableName作为最终的sql。实现原理就是自定义注解+反射,后期基于这种场景我也做了一些升级。第一次升级是因为有同事反馈说这种动态拼的sql是存在sql注入的,不推荐使用。于是我提供了一个新的重载方法,返回一个Map,两个k-v,一个是返回拼的sql,一个是返回对应的paramsList。第二次升级是因为在招聘系统中有些列表页的查询涉及到了多表查询,因此在查询dto上面基于单表的动态生成显然不满足,因此重构了一版,只要在注解上声明表的别名.字段名就行,使用方式跟原来一样。
对于上面提到的第二个问题就比较简单了,抽象了一个生成update 的语句,比如update tableName set status=0,update_user=1,update_time=now() where id=?。因此在后期的权限系统中经常有这种操作。那么在写daoimpl实现类中就不用显示的声明这样的sql了,传入几个参数返回sql,调用DAO框架提供DAOOperator.updateBySql()就可以了。
目前这个工具类已经在多个工程中应用,极大的解决了一些重复代码和稳定性问题。
- EnumsUtils工具类
痛点:这个工具类是为了解决当时招聘系统和corehr系统中存在的大量枚举(30+)而针对性的实现的一种统一的解决方案。招聘系统和corehr系统中的一些配置类的数据有些放到了公共数据配置平台里面以k-v的形式存储,有些就放在了代码里面,由于工程模块众多,很多枚举两个系统都要共用,一方面存在代码重复,另一方面对业务升级,前后端关于枚举数据的交互都复杂很多。
实现原理:java类加载和反射。通过指定要扫描的枚举包扫描枚举类,然后通过反射读取枚举中的属性值信息,并以Map<String,Map<String,String>>作为方法的返回值。
使用说明:该工具类有两个方法,用来解决从key到value的映射和value到key的映射。举个例子,比如我有员工类型枚举(StaffTypeEnum)0:正式员工,1:外包员工,2:顾问 这些数据。传入当前工程的包名,工具类自动扫描到这个枚举类,读取数据返回Map<String,Map<String,String>>格式的数据。从key到value的查找就是首先通过StaffTypeEnum类名去Map<String,Map<String,String>>找到这个枚举的子map,比如我想知道1代表什么类型的员工,直接从map中取就行了。相应的,从value到key也是同样的过程,只不过要调用另外一个方法。那么如果枚举中有多个属性数据呢,比如id,code,codeName这种三元组作为一个枚举元素的话,使用上面的方法怎么解决呢?其实在获取这个枚举元素的话方法里已经判断了枚举元素的个数,如果大于2个的话,那么默认第一个值是key,比如id是key,code和codeName就是value了,相反的,从value-key的映射也是以codeName作为key,id,code是value。多个属性值通过-符号拼接,业务代码自己处理需要的属性。不过这种枚举中存在多个值的情况比较少,一般都是k-v结构,或者单纯只有value. - 报表工具类
这里的报表工具类之前也做过一些,在一开始的物料管理系统中做过实践,当时我的项目组长使用了另外一个工具类基于JXL开发的。只是当时jxl有些限制,数据超过65535条之后就写不了了,也不支持高版本的excel.因此后期统一使用POI了。再后来基于easyexcel组件在corehr系统中解决了报表导入的问题。
maven插件&代码生成器
痛点:企业服务系统大量立项开发,众多项目开发需要手写大量entity,dto。光写这些基本半天时间过去了。
解决方案:当时想的一个解决方案就是基于maven插件去做,程序自动读取db.properties配置读取测试环境中的表数据,然后去动态生成。
实现:实际上实现是有点曲折的,由于maven本身版本的问题,导致插件在某些版本是无法运行的,另外一方面这种代码生成器实际上不应该放在pom.xml中被项目引用。因此后期又重新改版了一下。基于java jar+命令的方式实现。自定义xml配置,先读xml中的自定义配置,比如包,类的前后缀等。然后再初始化db链接。当时做了两个版本一个版本是基于公司DAO框架的,另外一个版本是基于JDBCUtils工具类的,向开源靠近。这个工具经过3次迭代才感觉让人满意,然后效果也不错。后期也跟架构部提供的这种代码生成工具做了一些对比,总体来说各有优势。虽然最后应用的次数不多,但是也成长许多。这个工具后来催生了部门领导和同事想搭建一个整体的代码生成器服务的想法,并正式立项开发了。我也合并了一些自己的代码~~。
orm框架daoclient
背景:写这个daoclient组件实际上是兴趣使然,当时花了一些时间看了公司的DAO框架,不同于mybatis和Hibernate,这有点新奇。简单点来说就是比较高级的JDBCUtils,加入了entity注解解析,结果集映射和编程式事务。
实现方案:基于java注解+反射实现,实现的过程中对java中的大多数数据类型做了处理,同时实现了相对简单的jdbc链接池。
git地址:https://gitee.com/codergit.com/daoclient
写文档生成器+接口自动化测试服务
背景:文档生成器其实很早就想动手去写了,主要是前后端分离和项目代码人员流动之后很多代码变得不容易懂了,业务文档也不多。另外一方面就是项目也比较多,有个统一的文档生成器和管理工具会更有效率。当时第一版本已经实现了扫描源码获取代码中的文档api信息了,后期由于项目时间紧张同时部门领导也不太支持这么干,有其他前端团队在搞,因此这个开发到了一半就停滞了。前端团队提供的接口api管理工具也比较原始各种手动输入,也没有自动化测试,被部门里很多开发同事吐槽,大概过了一年多后,我又重新设计了一版,将文档生成器和接口自动化测试整合到一起形成从开发到测试到文档维护等的整体功能闭环。
实现过程:在考虑实现的时候也考虑了下面三种方案1.maven插件2.java jar 3.直接读打包的class jar和源码Jar。经过各方面的考量决定使用第三种方式。于是在项目不是很忙的时候我又找回了第一版的代码,重新基于公司的RPC框架和WEB框架做了一些调研,在开始立项之前先咨询了各个技术部门的老大以及多位自身测试开发大佬。虽然有些负面反馈,但是我觉得还是可以尝试搞一搞的。
实现原理:
1.通过Maven编译插件打出class包,然后上传到文档生成器界面中,由程序自动通过类加载和反射的机制获取接口的接口包名,接口名,参数和返回类型等元数据,存储到数据库中。
2.通过maven 源码包插件打出源码包,然后上传到文档生成器界面上,由程序自动解析代码中的注释,存入数据库中。
3.将上述解析到的数据通过界面展示,然后录入对应的参数发起接口测试调用。
最终结果:项目的核心代码基本完成,多个服务的文档注释,元数据等都已存入数据库中。
fastjson升级工具
痛点:我所在的部门有众多工程服务,大量引用了fastjson jar包,由于fastjson从19年开始暴露出多个版本的严重bug导致部门内工程服务升级困难,升级时间延长。因此想通过一种方式去解决多个工程引入fastjson pom的问题,将低版本fastjson升级到高版本。
实现方案:调研java 通过jgit连接到远程git库,然后扫描本地项目的工作目录,将pom.xml读取出来,显示替换fastjson 为高版本,然后自动提交到远程仓库。
最终成果:我多次负责了部门内fastjson的升级工作,因此这个升级工具也跟着升级了2次。但是最终的使用效果却不太好。手动狗头~~
轻量级监控平台
痛点:我在企业信息部门的中后期做了一些系统调优的工作,发现在监控方面公司做的还不太够,虽然有了比较全的监控和报警。但是针对测试环境,针对线上环境的特定维度都还有些欠缺,也跟负责监控的同学聊了一下,另外跟运维的同事沟通了自己的想法。决定基于shell做一些轻量级监控的脚本和数据收集工作。
实现方案:基于Linux shell脚本实现机器ip,机器负载,机器内存磁盘,java服务,进程,线程,gc等信息的收集和上报,使用一个全局shell做脚本下发和脚本更新的工作。收集上报之后通过服务端的定时任务去扫数据结合钉钉机器人做报警。
最终成果:产出多个针对性的监控脚本,在测试环境中多次准确报警fgc,磁盘占满等情况,基于公司框架和springboot做了两套。虽然不够生产级的水准,但是可作为入门监控的一种选择。
说明:git地址中的代码没有监控脚本,为了安全考虑将涉及公司信息和公司代码的地方做了简化处理。相应的脚本已经在之前的博客中发布了,可以做对应的看。
git地址:https://gitee.com/codergit.com/lightmonitor
aop集成工具组件
痛点:我们部门负责的多个服务,在维护的过程中出现了一些排查困难,性能优化效率比较低,线上动态sql不知道怎么拼的问题。另外一方面接口参数调用校验也存在一些硬编码问题。
实现方案:1.集成公司架构部的DAO组件,RPC框架,Spring AOP,使用aop的多种通知方式结合自定义注解做方法执行拦截,声明式事务的提交回滚,sql打印等功能。
- 声明事务
- 编程事务
- 日志打印
- 参数校验
- 接口执行时间
- 内部方法执行时间
- sql打印
最终效果:组件整体实现了2个版本,同时在3个项目中实践,后期也规划了一些整合redis等功能的需求。
git地址:https://gitee.com/codergit.com/aop-scale
数据库表结构规范设计检测工具
痛点:这个工具源于一次关于数据库表设计的坑,当时要做动态报表的导出,报表涉及8张表,150+字段,任意选字段,任意导数据。在进行动态报表导出的时候需要对一些配置类的,枚举类的数据做一些变换,比如staffid换姓名,xxType换xxName这种的,因此实现之前需要对8张表的所有字段全部摸清分类,但是由于表字段和注释等不规范,整体方案落地过程中经常掉坑里。
实现方案:基于mysql的数据库表和字段的元数据做分析,并将不符合设计规范的地方收集起来,然后通过easyexcel或者输出控制台的方式去展现这些问题。
最终效果:整体功能基本完成,结合阿里巴巴java开发手册-数据库设计章节和公司数据库设计规范文档做基础,完成了多个场景的检测。目前通过开源框架重新实现了一个版本,已开源。
git地址:https://gitee.com/codergit.com/dbmodelcheck
高性能数据导出服务
背景:这个导出服务源于一次和同事的讨论,有个财务单据的导出需求,说要导出10万单据,貌似字段挺多的样子,意思是实现起来可能会有性能问题,先把需求怼回到产品吧。我这边想着能否写个工具去并行导出,提高导出性能。于是就自己捣鼓去了
实现方案:基于公司框架和java 8的并行api做异步导出和数据转换,另外整合easyexcel做报表的生成。
最终效果:整体功能基本完成,经过多轮测试30万数据最快5秒导出完成,虽然没有最终用到项目中,但是这确实是一个解决报表导出比较好方案。目前通过开源框架重新实现了一个版本,已开源。
git地址:https://gitee.com/codergit.com/commonreport
整体来说我可能并不是那么安分的去做分内之事,也不想在公司里真正的去摸鱼,总要追求一些东西,不断扩展自己的边界和能力。上面的工具,服务等虽然有些成功的应用到了企业系统中,有些失败了,甚至根本没有被实战过,但是至少我去尝试了,也算一种成长吧。对于上面的工具如果有你认可的,欢迎给个star哈。后续会另外创建系列文章讲述基于分布式微服务的租房架构设计实践,欢迎关注。
我最近整了一个公众号,持续输出原创内容,敬请关注:
架构设计@工程设计@服务稳定性之路
这篇关于企业服务架构演进-走上造轮子之路的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!