# gladys-framework **Repository Path**: openxgj/gladys-framework ## Basic Information - **Project Name**: gladys-framework - **Description**: 规范型自研框架,增强,一体化配置。 - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2020-12-26 - **Last Updated**: 2021-07-09 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # gladys-framework ## 背景 如何将一个项目写的更优雅更规范?我想从代码层面来思考这个问题。起初接到一个系统的重构需求,在浏览代码后,我发出感叹,怎么会有人将代码写的这么糟糕!?业务方法深层调用,if-else满天飞,我如何能将这样的系统重构,并且重新组织设计,并且让小组的人也能理解,将代码逻辑清晰化,时刻注意可读性、可扩展、可维护性、可测试性。 注:gladys-framework是为项目代码实现方案提供简单的指导,是在日常开发中,在项目中发现的问题积累而来,目的在于高开发效率、提升规范、提升代码可读性、可扩展性、可维护性和可测试性。 ## 设计 ### 1、基础类封装 网上很多这种例子,但是真正整理到一块的很少。 gladys提供项目所需基础类,例如 BaseRequest、BaseResponse、Result、BaseManager、BaseQuery、BaseContext、BasePage等 1. BaseRequest : 请求类基类,用于扩展和传递某些公有参数,也可自己再继承扩展,但是切勿继承过深。 2. BaseResponse: 响应类基类,效果和Request类似。 3. Result : 统一结果包装返回类,前端方便,后端也更加规范。 4. BaseManager : 可扩展的dao层抽象,我将平常会用到的些许crud接口都罗列了进来,应付日常所需开发足矣,特殊的查询等操作直接扩展出去即可。BaseManager屏蔽了一些细节,甚至能屏蔽掉orm框架,但是有几个要求,对于数据库需要有共有字段支持(强制性),条件查询统一BaseQuery为唯一传递介质,一张表一个Manager,单表Manager不可组合其他Manager(可读、可维护性、事务处理考虑),如果有多张表同时更新或修改,将主业务罗列出一个聚合Manager, 作为AggrManager 来操作。 ![输入图片说明](https://images.gitee.com/uploads/images/2021/0708/120855_2fb681e4_1805863.png "屏幕截图.png") 5. BaseQuery : 统一查询基类,子类以Builder方式构建查询条件。 6. BaseContext : 链式编程上下文,上下文传递。 7. BasePage : 统一分页对象。 基础类还有很多需要在日常工作中发现,目前后期还需扩展缓存基础类等,例如RedisKeyFactory, 将缓存的key作为一个对象封装起来,统一管理,免得出现这里一个那里一个key不知道往哪找的情况。 ### 2、链式编程(核心) 什么是链式编程?其实就是责任链模式,并且是可中断的责任链,类似于SpringMvc的过滤器、拦截器,就是我们将一个业务操作当做一个责任链,那么操作的细节就是链上一个个的节点。 我们可以将每一段业务操作,每一个接口看做一个责任链,这个接口可以包括三大要素。 1. 参数校验:对于一个请求,我们有必要做参数校验工作,如果图方便可以用javax的vaildation以注解形式做,也可以在业务逻辑中写。 2. 数据校验、数据查询:对于一个crud请求,免不了进行数据查询等校验,数据处理。 3. 数据保存、结果返回:得到最终数据,操作数据库或缓存等,得到最终结果并且返回。 **以上3种只是对于接口处理方式的一种抽象,真正在开发中,比较简单的操作,一个操作节点就可以了。** **链式编程如何实现?** 链式编程属于整个框架的核心,当有了以上的抽象之后,如何在代码中实现成了一个问题。 基础模型: ![输入图片说明](https://images.gitee.com/uploads/images/2021/0708/120924_e51cf2b0_1805863.png "屏幕截图.png") **Spring扩展:** 我们现在的项目基本上都是基于spring,bean由容器管理,spring为我们提供了扩展,例如各种Aware,BeanPostProcessor等,在bean的生命周期中,我们可以自定义一下规则,锁定ApplicationContextAware接口和BeanPostProcessor接口,当然我们也可以像dubbo那样注册事件来扩展,然后就是spring版本和jdk版本特性,基于注解驱动和泛型的支持。 **设计模式:** 1. 责任链模式:可中断式责任链模式,如果发现再执行中有false返回,立即中断并且返回。 2. 模板方法模式:统一方法由主类定义,BaseChain#execute, 子类实现自己的业务逻辑。 **面向对象设计:** 1. BaseChain : 链式基类,提供统一执行入口,提供Node组织集合。 2. Node : 接口,由子类实现。 3. GladysBeanPostProcessor : Spring后置处理,将Chain和对应的Node组织起来。 **详细实现见代码实现,不多赘述** ### 辅助组件 1. **灰度**: 为实现服务的平滑切换,用户无感知,通常我们灰度一般用在网关路由灰度,通过切流开关等配置,进行流量控制和回滚处理,但是基于接口方的灰度是与业务强关联的,要保证的是通过某个业务唯一标识,使请求落在唯一的服务上,gladys提供几种策略,实现流量控制,业务唯一标识命中分发服务功能。 注:该灰度组件需要可配置可发布化开关支持,用于开启和关闭灰度功能,并且对代码有小量的入侵,但是该入侵只针对下游业务,上游业务无感知。 **id分段策略:** 对于业务中有唯一标识的id时,可进行id分段, 调整分段区间大小, 如图所示, 如果id尾数在0~5, 在这个区间段的所有请求都将在serviceA上进行, 反之 6~9 的会请求到serviceB。 权重比:可根据配置, 设置分段大小。例如: 为serviceA配置分段比例 80 %, 理论上, 如果id尾数分布均匀, 80% 的请求都会指向 serviceA,即尾数为 0 ~ 7 的请求指向 serviceA, 8和9指向 serviceB。 serviceA优先。 ![输入图片说明](https://images.gitee.com/uploads/images/2021/0708/120949_c8927b1a_1805863.png "屏幕截图.png") 优点: 计算简单, 可控性强,易配置, 追踪方便。 缺点: 业务唯一标识只支持数字类型, 字符串类型无法处理, 分段过于集中, 特殊情况无法处理。 **hash+bitmap占位:** 首先生成一个8个或16个长度的byte数组, 根据业务标识进行hash计算, 再根据数组长度和hash值进行与运算(此原理用的是hashmap的处理方式), 我们可以预先随机几个值配置在数组中初始化好, 然后根据hash运算和与运算的结果去数组中取, 能取到 走 serviceB, 反之 走 serviceA, 注: 能取到才指向serviceB的原因是, 我们是对B服务进行灰度, 而不是A服务。原理如下图: ![输入图片说明](https://images.gitee.com/uploads/images/2021/0708/121009_7ad8dd56_1805863.png "屏幕截图.png") 优点: 支持所有数据格式, 权重可配置, 随机性强, 分布均匀, 可控, 可追踪。 缺点: 会小量消耗内存, 难理解。 补充:根据业务值的hash算法,在实际业务场景中可能受到某些热场景数据的影响导致实际的流量发生倾斜 **随机算法(暂未实现):** 利用随机数算法生成0-99范围内的随机整数,根据分流比例值,例如:30,将小于等于30-1的值切分到serviceA其余划分到serviceB 优点:不依赖业务数据,实际流量分配最均匀,实现方式简单,性能好 缺点:没有辅助追踪流量的功能 2. 限流(未实现) / 3. 监控(未实现) 利用云服务可以直观的看到,各个接口的调用情况,rt,qps等,但是要收费。对于监控组件的设计,可以依赖于链式Chain调用时监控,或者利用aop对Controller监控,需要支持业务无入侵可插拔。 1. 数据收集:尽可能的将接口调用有关的所有信息汇集,例如每秒请求次数,响应时间,失败次数,接口失败率等能想到的。 2. 数据显示:可以以日志的形式输出,或者更高级的就是,异步推送到自研的监控平台。 由于个人时间原因和需求度,部分功能还在完善中,并且这类功能需要得到有利的测试和流量冲击才能投入生产。 ## 缺点 链式编程存在的缺点很明显,每个节点之间的事务是不能保证的,所以需要将写操作都集中起来统一,并且为了减少Mysql锁占用时长,提升并发能力,将并发度高的尽量语句挪到最后执行,这就需要对最后一个数据保存环节有一个良好的设计。 ## 后续工作 不断的引入项目所需,优化代码和结构。