# dyna-guard
**Repository Path**: vd3/dyna-guard
## Basic Information
- **Project Name**: dyna-guard
- **Description**: 基于 Java 的动态验证框架,配置+脚本+热更新的方法来实现业务逻辑验证/业务规则获取
- **Primary Language**: Java
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 117
- **Forks**: 3
- **Created**: 2025-08-16
- **Last Updated**: 2025-09-16
## Categories & Tags
**Categories**: utils
**Tags**: 实时熔断, 规则引擎, 规则表达式追踪, 业务逻辑验证, 业务规则获取
## README
# dyna-guard - 动态校验框架
dyna-guard 是一个基于 Java 的动态校验框架,使用配置 + 脚本 / 规则引擎 +
热更新的方式让企业中的业务校验更加动态,并且还提供了熔断机制对于敏感业务能够有效的提供保护,以及对于校验触发条件的统计,让业务能够更好的感知业务卡点,为以后的业务发展方向能够分析以及制定方案。
## 技术文档 [点击进入](https://www.yuque.com/yuqueyonghuqdqyqs/kswtr7)
## 示例项目 [点击进入](https://github.com/vdd3/dyna-guard-example)
## 项目结构
```
dyna-guard/
├── dyna-guard-core/ # 核心模块,包含校验引擎、规则解析等核心功能
├── dyna-guard-engine/ # 引擎模块,包含不同的规则引擎
└── dyna-guard-spring-boot-starter/ # Spring Boot Starter,提供自动配置和集成支持
```
## 技术架构
dyna-guard 采用模块化设计,核心模块与 Spring Boot Starter 分离,便于在不同环境中使用:
1. **核心模块** (`dyna-guard-core`) 提供基础的校验能力
2. **Spring Boot 集成模块** (`dyna-guard-spring-boot-starter`) 提供自动配置和 Spring 集成
3. **引擎模块** (`dyna-guard-engine`) 提供不同的规则引擎,如 Groovy、JavaScript和Aviator
框架通过 SPI (Service Provider Interface) 机制实现插件化扩展,支持动态加载不同的校验器、解析器等组件。
## 功能特性
- **多规则引擎支持**:支持 Groovy、JavaScript、QLExpress4 和 Aviator
- **灵活的校验链机制**:通过配置定义校验节点,支持多种数据源(JSON、XML、SQL)
- **Spring Boot 集成**:提供 Starter 模块,开箱即用
- **动态规则加载**:支持从本地文件、数据库等多种来源加载校验规则
- **熔断机制**:内置计数器熔断器,防止系统过载
- **AOP 拦截**:方法级校验拦截,实现自动执行校验过程
- **插件机制**:支持动态加载不同的校验器、解析器等组件
- **校验追踪**:支持校验追踪,记录拦截的触发条件,可以让用户对拦截的业务进行感知并且进行分析
## 安装使用
### Maven 依赖
```xml
cn.easygd
dyna-guard-spring-boot-starter
0.0.6-beta
```
#### 额外的语言选择
从0.0.5版本开始框架本身不额外引入其他语言的情况下只支持QLExpress4,如果需要其他的语言,请自行引入对应的依赖
```xml
cn.easygd
dyna-guard-groovy
0.0.6-beta
```
```xml
cn.easygd
dyna-guard-aviator
0.0.6-beta
```
```xml
cn.easygd
dyna-guard-javascript
0.0.6-beta
```
### 基本配置
在 `application.yml` 中添加配置:
```yaml
validation:
# 解析器的配置,获取校验链时若未指定group,将根据解析器优先级获取对应group下的流程
parser: sql,xml,json
# 解析文件路径的解析器名称,一般无需设置,使用框架默认解析器
pathParserName: spring
# 需要拦截的类,若使用方法级别校验,设置为需要拦截的类名称
validationMethod: **Service
# 安全策略
enableSecurityStrategy: false
# 链路追踪
enableBizTrace: false
# 流程文件的路径,支持多个路径,用英文逗号分隔
chainFilePath: classpath:chain/*Chain.xml,classpath:chain/*Chain.json
# SQL数据存放chain的配置(用于连接数据库及字段映射,默认开启监听)
sqlChainDataMap:
enableListener: true
url: jdbc:mysql://localhost:3306/db
driverClassName: com.mysql.cj.jdbc.Driver
username: root
password: root
# 监听器线程池核心线程数(定时任务实现)
corePoolSize: 1
# 第一次任务的间隔时间(秒)
firstListenerInterval: 120
# 后续任务的间隔时间(秒)
listenerInterval: 300
tableName: validation_chain
createTimeField: create_time
updateTimeField: update_time
chainIdField: chain_id
deletedField: deleted
orderField: order
messageField: message
fastFailField: fast_fail
languageField: language
scriptField: script
nodeNameField: node_name
# XML存放chain的配置(用于xml标签映射及监听器)
xmlChainDataMap:
enableListener: true
# 监听文件的路径
listenerFileList: classpath:chain/*Chain.xml
# 监听文件的间隔
listenerInterval: 5
guardExpireField: guardExpire
guardThresholdField: guardThreshold
chainField: chain
chainIdField: id
nodeField: node
languageField: language
orderField: order
messageField: message
fastFailField: fastFail
nodeNameField: name
# JSON存放chain的配置(用于json字段映射及监听器)
jsonChainDataMap:
enableListener: true
# 监听文件的路径
listenerFileList: classpath:chain/*Chain.json
# 监听文件的间隔
listenerInterval: 5
guardExpireField: guardExpire
guardThresholdField: guardThreshold
chainIdField: chainId
nodeField: node
languageField: language
orderField: order
messageField: message
fastFailField: fastFail
scriptField: script
nodeNameField: name
```
在 `application.properties` 中添加配置:
```properties
# 解析器的配置,获取校验链的时候如果没有指定group会根据解析器的优先级获取对应group下的流程
validation.parser=sql,xml,json
# 解析文件路径的解析器名称,一般不用设置,直接根据框架默认的解析器即可
validation.pathParserName=spring
# 需要拦截的类,如果想使用方法级别校验,请将此参数设置为需要拦截的类名称
validation.validationMethod=**Service
# 流程文件的路径,支持多个路径,多个路径用英文逗号隔开
validation.chainFilePath=classpath:chain/*Chain.xml,classpath:chain/*Chain.json
# 安全策略,如果开启,脚本中无法对参数内容进行修改
validation.enableSecurityStrategy=false
# 链路追踪
validation.enableBizTrace=false
# sql数据存放chain的配置,主要用于连接数据以及对字段的映射,默认开启监听
validation.sqlChain-data-map[enableListener]=true
validation.sqlChainDataMap[url]=jdbc:mysql://localhost:3306/db
validation.sqlChainDataMap[driverClassName]=com.mysql.cj.jdbc.Driver
validation.sqlChainDataMap[username]=root
validation.sqlChainDataMap[password]=root
# 监听器是使用定时任务线程池实现的,这个是线程池的核心线程数
validation.sqlChainDataMap[corePoolSize]=1
# 第一次任务的间隔时间(秒)
validation.sqlChainDataMap[firstListenerInterval]=120
# 后续任务的间隔时间(秒)
validation.sqlChainDataMap[listenerInterval]=300
validation.sqlChainDataMap[tableName]=validation_chain
validation.sqlChainDataMap[createTimeField]=create_time
validation.sqlChainDataMap[updateTimeField]=update_time
validation.sqlChainDataMap[chainIdField]=chain_id
validation.sqlChainDataMap[deletedField]=deleted
validation.sqlChainDataMap[orderField]=order
validation.sqlChainDataMap[messageField]=message
validation.sqlChainDataMap[fastFailField]=fast_fail
validation.sqlChainDataMap[languageField]=language
validation.sqlChainDataMap[scriptField]=script
validation.sqlChainDataMap[nodeNameField]=node_name
# xml存放chain的配置,主要用于xml标签的映射,以及监听器
validation.xmlChainDataMap[enableListener]=true
# 监听文件的路径
validation.xmlChainDataMap[listenerFileList]=classpath:chain/*Chain.xml
# 监听文件的间隔
validation.xmlChainDataMap[listenerInterval]=5
validation.xmlChainDataMap[guardExpireField]=guardExpire
validation.xmlChainDataMap[guardThresholdField]=guardThreshold
validation.xmlChainDataMap[chainField]=chain
validation.xmlChainDataMap[chainIdField]=id
validation.xmlChainDataMap[nodeField]=node
validation.xmlChainDataMap[languageField]=language
validation.xmlChainDataMap[orderField]=order
validation.xmlChainDataMap[messageField]=message
validation.xmlChainDataMap[fastFailField]=fastFail
validation.xmlChainDataMap[nodeNameField]=name
# json存放chain的配置,主要用于json字段的映射,以及监听器
validation.jsonChainDataMap[enableListener]=true
# 监听文件的路径
validation.jsonChainDataMap[listenerFileList]=classpath:chain/*Chain.json
# 监听文件的间隔
validation.jsonChainDataMap[listenerInterval]=5
validation.jsonChainDataMap[guardExpireField]=guardExpire
validation.jsonChainDataMap[guardThresholdField]=guardThreshold
validation.jsonChainDataMap[chainIdField]=chainId
validation.jsonChainDataMap[nodeField]=node
validation.jsonChainDataMap[languageField]=language
validation.jsonChainDataMap[orderField]=order
validation.jsonChainDataMap[messageField]=message
validation.jsonChainDataMap[fastFailField]=fastFail
validation.jsonChainDataMap[scriptField]=script
validation.jsonChainDataMap[nodeNameField]=name
```
### 使用示例
在springBoot项目启动类上添加 [@EnableValidation] `加上这个注解springboot启动时会自动加载一整套流程`
#### 自动执行校验流程
在配置文件中配置 `validation.validationMethod` 定义需要拦截的类,可以使用通配符
在需要校验的方法实现类上添加 [@DynamicGuard]注解
```java
@Service("simpleService")
public class SimpleServiceImpl implements SimpleService {
/**
* 单个脚本为校验链
*
* @param param 请求参数
*/
@DynamicGuard(group = "json", chainId = "user.create")
@Override
public void oneNode(Param param) {
System.out.println("校验通过");
}
/**
* 多脚本组合为校验链
*
* @param param 请求参数
*/
@DynamicGuard(group = "xml", chainId = "user.update")
@Override
public void moreNode(Param param) {
System.out.println("校验通过");
}
/**
* 按照优先级匹配校验链分组
*
* @param param 请求参数
*/
@DynamicGuard(chainId = "user.create")
@Override
public void sqlNode(Param param) {
System.out.println("校验通过");
}
/**
* 熔断
*
* @param param 请求参数
*/
@Override
@DynamicGuard(chainId = "user.create",
// 启用熔断
enableGuard = true,
// 熔断模式,可选:COUNTER,RATE
guardMode = GuardMode.COUNTER,
// 熔断阈值的json格式
guardThreshold = "{\"threshold\":100,\"period\":10,\"fail\":true}"
)
public void guard(Param param) {
System.out.println("校验通过");
}
}
```
#### 自行执行校验流程
业务级验证流程, 在业务逻辑中调用显式的调用流程
```java
public class BizService {
public void guardInBiz(Param param) {
// 1.构建校验流程上下文
ValidationContext context = new SpringValidationContext();
// 如果需要熔断可以设置对应的参数,优先级按照每个流程的设置来,全局的熔断配置不影响流程单独配置的熔断参数
ChainOptions chainOptions = ChainOptions.builder()
// 启用熔断
.enableGuard(true)
// 熔断模式,可选:COUNTER,RATE
.guardMode(GuardMode.RATE)
// 熔断阈值
.guardThreshold(new InterceptRateThreshold())
.build();
context.setChainOptions(chainOptions);
// 2.获取验证链再执行
ValidationChain chain = null;
chain = ChainExecutorHelper.getChain("您的验证链ID");
chain = ChainExecutorHelper.getChain("您想使用的存储流程的分组", "您的验证链ID");
// 直接抛出异常的执行
chain.execute(context);
// 带返回值的执行
ValidationResult result = chain.executeResult(context);
// 根据返回值中的信息处理
// 工具类直接执行
ChainExecutorHelper.validateHere("您的验证链ID", context);
ChainExecutorHelper.validateHere("您想使用的存储流程的分组", "您的验证链ID", context);
}
}
```
2. 定义校验链配置:
`json格式`
```json
[
{
"chainId": "user.create",
"node": [
{
"order": 1,
"name": "参数校验节点",
"script": "",
"language": "",
"message": "参数不能为空",
"fastFail": true
}
]
}
]
```
`xml格式`
```xml
0) {
if("admin" in roleList){
// 获取用户数据权限
def dataRoleList = roleService.getDataRoleList(workNo);
return "update" in dataRoleList;
}
}
return flag;
]]>
```
## 扩展开发
### 自定义校验器
实现 [Validator]或者继承[BaseValidator]接口并注册到 SPI:
```java
public class CustomValidator extends BaseValidator {
@Override
public Object compile(String script) throws Exception {
// 编译逻辑,实现这个逻辑后可对脚本进行编译缓存
return null;
}
@Override
public Boolean validate(String script, ValidationContext context) {
// 实现校验逻辑
return true;
}
@Override
public String getLanguage() {
return "custom";
}
}
```
在 `META-INF/services/com.easytu.dynaguard.core.engine.Validator` 文件中添加实现类:
```
com.example.CustomValidator
```
### 自定义业务校验统计器
`业务校验统计器的意义在于让您对自己的业务进行分析,比如某块业务因为什么条件导致一直被拦截`
实现[BizValidationStatistics]或者继承[BaseBizValidationStatistics]并且注册到spring中,如果不自定义,会使用框架默认的统计器,但是无法做到数据持久化以及分布式系统统计
```java
public class CustomBizValidationStatistics extends BaseBizValidationStatistics {
/**
* 调用次数加1
*
* @param chainId 链ID
*/
@Override
public void incrementCount(String chainId) {
}
/**
* 调用成功次数加1
*
* @param chainId 链ID
*/
@Override
public void incrementPassedCount(String chainId) {
}
/**
* 熔断次数加1
*
* @param chainId 链ID
*/
@Override
public void incrementGuardCount(String chainId) {
}
/**
* 拦截次数加1
*
* @param chainId 链ID
* @param nodeName 节点名称
* @param condition 拦截条件
*/
@Override
public void incrementValidationCount(String chainId, String nodeName, String condition) {
}
/**
* 获取调用次数
*
* @param chainId 链ID
* @return 调用次数
*/
@Override
public Long count(String chainId) {
}
/**
* 获取通过次数
*
* @param chainId 链ID
* @return 通过次数
*/
@Override
public Long passedCount(String chainId) {
}
/**
* 获取熔断次数
*
* @param chainId 链ID
* @return 拦截次数
*/
@Override
public Long guardCount(String chainId) {
}
/**
* 获取拦截次数
*
* @param chainId 链ID
* @param nodeName 节点名称
* @param condition 拦截条件
* @return 拦截次数
*/
@Override
public Long validationCount(String chainId, String nodeName, String condition) {
}
/**
* 节点拦截次数
*
* @param chainId 链ID
* @param nodeName 节点名称
* @return key 拦截条件 value 拦截次数
*/
@Override
public Map nodeValidationCount(String chainId, String nodeName) {
}
/**
* 链拦截率
*
* @param chainId 链ID
* @return 拦截率
*/
@Override
public BigDecimal chainValidationRate(String chainId) {
}
/**
* 链拦截指标
*
* @param chainId 链ID
* @return 拦截指标
*/
@Override
public List validationMetrics(String chainId) {
}
}
```
### 自定义熔断器
#### 计数熔断器
实现[CounterGuard]
```java
@Commpent
public class CustomCounterGuard implements CounterGuard {
@Override
public List chainId() {
// 如果返回为空则代表全局的计数熔断都会使用这个熔断器
return null;
}
@Override
public Boolean isExceedThreshold(String chainId, GuardThreshold guardThreshold) {
CounterThreshold counterThreshold = (CounterThreshold) guardThreshold;
// 判断是否超过了阈值,超过阈值会执行降级操作
return null;
}
@Override
public Long increment(String chainId) {
// 自增
return null;
}
@Override
public Long getCount(String chainId) {
// 获取当前失败的次数
return;
}
@Override
public void clear(String chainId) {
// 清除
}
@Override
public void fallBack(String chainId, ValidationContext context) {
// 在这里实现降级逻辑
}
}
```
#### 拦截率熔断器
`拦截率熔断器的应该是要配合业务校验统计器使用的,目的就是为了在达到一定阈值时进行降级操作`
实现[InterceptRateGuard]
```java
public class CustomInterceptRateGuard implements InterceptRateGuard {
/**
* 链路ID
*
* @return 链路ID
*/
@Override
public List chainId() {
// 如果返回为空则代表全局的计数熔断都会使用这个熔断器
return null;
}
/**
* 是否超过阈值
*
* @param chainId 流程id
* @param guardThreshold 熔断阈值
* @return true 超过阈值
*/
@Override
public Boolean isExceedThreshold(String chainId, GuardThreshold guardThreshold) {
InterceptRateThreshold interceptRateThreshold = (InterceptRateThreshold) guardThreshold;
// 这里实现判断阈值的逻辑
return true;
}
/**
* 降级操作
*
* @param chainId 链路ID
* @param context 上下文
*/
@Override
public void fallBack(String chainId, ValidationContext context) {
// 在这里实现降级逻辑
}
}
```
```
自己定义的熔断器都需要注册到spring中
```
## 贡献指南
欢迎提交 Issue 和 Pull Request 来改进 dyna-guard。
## 许可证
[Apache 2.0]
## 联系方式
