# bean-validator
**Repository Path**: sunskych/beanvalidator
## Basic Information
- **Project Name**: bean-validator
- **Description**: 基于javabean的校验器
- **Primary Language**: Java
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 2
- **Forks**: 0
- **Created**: 2021-07-11
- **Last Updated**: 2023-12-20
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# bean-validator
#### 介绍
基于javabean对象的校验器,适用于校验规则特别多的场景,cpu密集型任务,解决校验规则复用问题、硬编码可维护性。
**功能特点:**
·用文档描述规则,跳出代码层面;便于阅读、维护,无需编译;
·根据java对象自动生成规则文档模版。解决绝大部分工作量问题;
·引入观察者设计模式,便于开发测试过程规则执行结果的快速分析。
**性能优化:**
·动态字节技术,javassist动态字节码,初始化时直接生成代理取值的java字节码方法,以达到空间换时间的目的。
·依赖规则缓存,避免重复执行;
·无状态应用组件:
·构建无状态组件,一次初始化,重复使用,避免频繁创建对象操作。
·分析校验行为,确定接口: 校验的值、所在段(对象) 、全局记录(对象)、上下文对象—>方法参数传入; 校验结果—>方法返回值 .
**编码要点:**
规则文档在构建验证器时,需要解决的几个要点.
·取值:规则描述的当前属性值。规则依赖的其他属性值
·逻辑运算:多个依赖规则的逻辑运算条件成立
·算术运算:规则描述的算术运算。
-> 识别行为(方法),定义角色(接口)。
#### 调研
1. 取值及取值表达式,程序如何获取到值?反射或者是现有SpringEL表达式工具?注意性能
取值性能分析
| 压测笔数 | 硬编码耗时,毫秒 | 反射耗时 | springel |
| -------- | ---------------- | -------- | -------- |
| 10万 | 10 | 15 | 1012 |
| 100万 | 25 | 42 | 3759 |
| 1000万 | 20 | 105 | 19984 |
| 1亿 | 13 | 778 | 208127 |
| 10亿 | 26 | 4392 | |
考虑适应百万量级数据,且每条数据规则上百条以上的场景,会对cpu进行密集型资源消耗。为应对此场景,采用动态字节码技术模拟硬编码达到最优。
2. 算术表达式,如何实现算术表达式逻辑。5+9*3
| 压测笔数 | rpn自实现,cost mill | google aviator | |
| -------- | -------------------- | -------------- | ---- |
| 10万 | 268 | 346 | |
| 100万 | 1396 | 1607 | |
| 1000万 | 12480 | 12626 | |
| 1亿 | 124006 | 122563 | |
| 10亿 | 1293296 | 1324115 | |
cpu、内存指标稳定;
#### 软件架构
##### 软件设计说明
**1 设计规则文档。**
1.1 结构问题:与对象结构一致。-->对应xml元素包含结构。
1.2 如何描述规则问题:抽象出规则的概念,可描述规则通用信息。概念上对规则进行分析,从而对规则进行分类定义规则类型。然后在对具体的规则类型进行描述。 ( 抽象,提取规则类型,明确范围,规则描述; 属性+规则类型+规则描述-->构成一个完整的规则。)
**示例:**
```xml
```
1.3 示例,规则概念对应 ;rule元素与子元素proerty一起完成规则描述。
**2 规则___细节描述的内容如何设计??**
1.1 作为规则时,描述内容该如何落地?
一般的'操作'、'逻辑'、'常量' 等静态说明,都都可以通过 方式注入。
重点如解决非静态描述问题,非静态主要有动态取值和算术运算问题,下面我将结合场景进行分析及设计。
1.1.1 规则描述中需要动态属性值,或预系统中预设置的内容(比如参数,字典缓存等)。
a. 可以获取在上下文中预设置内容,定义特定取值表达式和关键词进行描述。
b. 从校验的全局对象中,通过属性名称作为关键词(全局路径)进行描述,
c. 从校验属性的所属对象中,通过属性名称作为关键词(单级子属性名)进行描述。已经有全局路径取值还有必要单级子属性名取值吗?实际的应用场景中可能 涉及到一个集合中对应的属性之间描述依赖,故而需要。
1.1.2 规则描述中设计算术运算
a. 常量 算术运算符 常量
b. 动态取值 算术运算符 常量
c. 动态取值 算术运算符 动态取值
1.2 作为被依赖条件时,该如何解决校验属性v取值问题?
a. 取到这个被依赖规则的对应属性的值? 根据属性的结构关系,可获取到它的已知全局路径($bean.xxx.xx)关键词。
b. 集合中对象属性规则被同对象中的其他属性依赖场景:单级子属性名方式可以解决($local.xxx)。全局路径方式无法适用,原因是集合中多个对象,无法确定是哪一个对象的属性的规则;
c. 集合中对象属性规则被其他对象中的属性依赖场景:不论是全局还是单级子属性名方式都无法解决,但是这种场景实际中是否存在呢?(仔细想好像可能性极小)。但是也要考虑到实在无法实现的复杂场景。引入超级扩展方式(手写java代码)。
**3 编码设计**
**构建过程**
a 扫描规则文件路径; 解析为元数据; 定义过程,数据规范基本检查与准备工作;
b 构建Ichecker; 依据规则描述创建checker及行为。
c 构建执行引擎fieldValidator;依据描述结构field和rule(checker)加入fieldValidator中。放入缓存FieldValidatorCache中。
d 在构建时,同时需要生成不同的功能的处理者或者代理者,比如各种取值处理者、依赖处理者。
d 提供工厂根据id获取验证器实例,以供用户使用。
**接口设计**
1.1 元数据:ValidateRules、ValidateRule、Field、FieldRule、Property
1.2 执行组件接口:
a IChecker rule对应检查器-->职责:
作为角色时的规则执行者(输入:校验的值、所在对象,全局对象,上下文对象{可预设系统参数,在实行器内部根据key获取} ;输出:反馈对象 );
作为条件时的条件执行者(输入:校验的值、所在对象,全局对象;输出:boolean是否成立 )
b FieldValidator java对象规则集对应的验证器-->职责: 规则集的执行引擎。(概念上同class的属性)规则引擎实现、v取值实现,组合模式。
1.3 引擎部件接口?
a IValidator\BeanValidator(对FieldValidator进行包装,屏蔽细节,对用户提供服务);>职责: 规则集的执行引擎。(输入:java对象;输出:反馈对象集合)。
1.4 一个checker实现
a 解决《2 规则___细节描述的内容如何设计》的实现。
1.5 组件创建接口
a IValidatorRulesParser-->职责:规则内容解析为实体元数据对象。1.规则原始形态对象;2.规则文件解析为原形态实体对象结构。
b IValidatorRuleDefiner-->职责: 明确验证器规则描述实体对象;基本规范检查和准备工作。
c ValidatorBulider-->职责:核心代码,将一个规则描述实体创建为一个FieldValidator规则执行引擎。
d ValidatorLoader-->职责:上述加载过程。
**代码细节**
·识别职责(行为)—>划分角色(类)
·要想清楚运行时状态时或者周生命周期—>代码实现方式
· 所有的运行代码都应是无状态的,错误代码、规则本身的表达数据(规则描述、依赖)在创建阶段赋值后不在变化。
··有状态的数据:校验的值、所在对象,全局对象—>方法参数传入;错误返回结果—>返回值 .
####
##### 软件内嵌机制
1. 当一个规则不满足时,是否继续执行该field的其他规则(策略todo)。
2. 当一个javabean中的校验错误达到最大错误数时,不再继续执行(上下文中允许最大错误数设置决定)。
安装教程
xxxx
xxxx
xxxx
**使用说明**
**语法说明书:**
src/main/resources/validator说明书.xlsx
**样例:**
src/test/java/com/ssky/demo/TestMain.java
src/test/resources/earth-validator.xml
xxxx
xxxx
xxxx
参与贡献
Fork 本仓库
新建 Feat_xxx 分支
提交代码
新建 Pull Request