# rule_engine
**Repository Path**: ahaow/rule_engine
## Basic Information
- **Project Name**: rule_engine
- **Description**: Drule业务规则可视化平台。基于Drools 封装的业务规则可视化平台,用于简化规则开发,将规则表达式、规则条件和规则动作等进行可视化展示,并降低学习和开发成本,帮助用户快速创建业务规则。并在其基础之上,拓展更多功能,如规则文件的变更差异、规则对象的热加载、KieBase管理与监控、规则执行信息监控等。
- **Primary Language**: Java
- **License**: MulanPSL-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 33
- **Forks**: 19
- **Created**: 2024-08-27
- **Last Updated**: 2026-04-23
## Categories & Tags
**Categories**: rule-engine
**Tags**: Java, drools, 规则引擎, 可视化编辑, DRULE
## README
# Drule
> 基于 Drools 封装的业务规则可视化平台
[](https://www.oracle.com/java/)
[](https://www.drools.org/)
[](https://groovy-lang.org/)
[](LICENSE)
## 📚 介绍
Drule 是一个业务规则可视化平台,基于 Drools 规则引擎进行封装,旨在简化规则开发流程。平台将规则表达式、规则条件和规则动作等进行可视化展示,降低学习和开发成本,帮助用户快速创建业务规则。
### 核心特性
- 🎨 **可视化规则编辑** - 通过可视化界面配置规则条件和动作,无需编写 DRL 代码
- 🔄 **热加载支持** - 规则对象支持热加载,无需重启服务即可更新规则
- 📊 **规则差异对比** - 支持规则文件的变更差异可视化展示
- 🔍 **中文转译** - 将规则内容转译为中文,便于业务人员理解
- 📈 **执行监控** - 提供 KieBase 管理与监控、规则执行信息监控等功能
- 🧩 **灵活扩展** - 提供丰富的扩展点,支持自定义前置/后置处理器、监听器等
- 🆕 **BPMN 流程支持** - 支持 BPMN 2.0 流程编译和执行,可视化流程定义
- 🚀 **3 层嵌套条件** - 支持复杂的对象层次结构(SuperGroup → ConditionGroup → Condition)
- ⚡ **性能优化** - TreeNode 查找缓存(LRU 策略),编译性能显著提升
- 🏗️ **架构升级** - 编译器模块化重构,职责分离清晰,易于扩展和维护
- 📜 **脚本引擎** - SPI 可插拔脚本引擎架构,内置 Groovy 支持,规则执行前通过脚本加工变量
- 🔀 **并行网关** - BPMN 并行网关支持,实现流程分支的并行执行与聚合
## 🌈 体验地址
- **在线演示**:[Drule平台](http://ahaoweb.cn/drule/visual)
- **账号**:test
- **密码**:123456
- **使用文档**:[CSDN 专栏](https://blog.csdn.net/qq_51513626/category_12897737.html)
## 🪙 技术栈
| 技术 | 版本 | 说明 |
|------|------|------|
| Java | 8+ | 基础运行环境 |
| Drools | 7.60.0.Final | 规则引擎核心 |
| jBPM | 7.60.0.Final | 🆕 BPMN 流程引擎 |
| Groovy | 2.5.23 | 🆕 脚本引擎(SPI 实现) |
| Jackson | - | JSON 序列化/反序列化 |
| Lombok | 1.18.30 | 简化代码 |
| JUnit 5 | 5.9.3 | 单元测试 |
| Mockito | 4.11.0 | Mock 测试 |
## 🏗️ 架构设计
### 整体架构
```
┌─────────────────────────────────────────────────────────────────────────────────┐
│ Drule 规则引擎平台 v2.1 │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ │ │ │ │ │ │
│ │ drule- │─────▶│ drule- │─────▶│ drule- │ │
│ │ models │ │ compile │ │ execute │ │
│ │ │ │ │ │ │ │
│ │ 对象配置模块 │ │ 编译器模块 │ │ 执行引擎模块 │ │
│ │ │ │ │ │ │ │
│ │• TreeNode │ │• DRL编译 │ │• RuleService│ │
│ │• 结构扫描 │ │• 对象划分 │ │• RuleSession│ │
│ │• LRU缓存 │ │• 表达式编译 │ │• 会话管理 │ │
│ │ │ │• 规则校验 │ │• 监听器体系 │ │
│ └─────────────┘ │ │ │• 变量加工🆕 │ │
│ │ │ └──────┬──────┘ │
│ │ │ │ │
│ │ ┌──────────┴──────┐ │ │
│ │ │ │ │ │
│ │ │ drule-jbpm │──────┘ │
│ │ │ 🆕 v2.0 │ │
│ │ │ │ │
│ │ │ BPMN流程模块 │ │
│ │ │ │ │
│ │ │• BPMN编译 │ │
│ │ │• 流程执行 │ │
│ │ │• XML转义 │ │
│ │ │• 中文翻译 │ │
│ │ │• 并行网关🆕 │ │
│ │ └─────────────────┘ │
│ │ │
│ │ ┌─────────────┐ ┌─────────────────────────────┐ │
│ │ │ │ │ │ │
│ └─▶│ drule- │ │ drule-script 🆕 v2.1 │ │
│ │ parse │ │ 脚本引擎 SPI 接口层 │ │
│ │ │ │ │ │
│ │ DRL解析模块 │ │• ScriptEngine SPI │ │
│ │ │ │• ScriptContext │ │
│ │• DRL解析 │ │• ScriptConfig │ │
│ │• 语法树构建 │ │• ScriptOutputDataType │ │
│ │• 元素提取 │ │• ScriptEngineProvider │ │
│ │ │ │ │ │
│ └─────────────┘ └─────────────────────────────┘ │
│ │
├─────────────────────────────────────────────────────────────────────────────────┤
│ drule-spi 🆕 v2.1 SPI 实现聚合模块 │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ drule-groovy │ │
│ │ Groovy 脚本引擎实现(通过 ServiceLoader 自动注册) │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
├─────────────────────────────────────────────────────────────────────────────────┤
│ 底层引擎:Drools 7.60.0.Final + jBPM 7.60.0.Final │
└─────────────────────────────────────────────────────────────────────────────────┘
数据流向说明:
1. drule-models:扫描 Java 对象,构建 TreeNode 树形结构(支持 LRU 缓存)
2. drule-compile:将可视化规则编译为 DRL 代码(支持 3 层嵌套、对象划分、AdvanceVariable 字段路径)
3. drule-jbpm:将 BPMN 流程编译为 jBPM XML(支持多种节点类型,含并行网关)
4. drule-parse:解析 DRL 文本,构建语法树(支持反向工程)
5. drule-execute:执行规则/流程,管理会话生命周期(支持监听器、变量加工处理器)
6. drule-script:脚本引擎 SPI 接口层,定义脚本执行规范(ScriptEngine、ScriptContext)
7. drule-spi/drule-groovy:Groovy 脚本引擎 SPI 实现,支持预编译缓存
```
### 模块说明
```xml
drule-core
drule-spi
```
`drule-core` 是 Drule 的核心包,当前版本包含以下 6 个模块:
| 模块 | 说明 | 核心功能 |
|------|------|----------|
| `drule-models` | 对象配置模块 | 规则对象结构扫描、TreeNode 构建、LRU 缓存 |
| `drule-compile` | 内容编译模块 | 可视化结构编译为 DRL、规则校验、中文转译、对象层次划分、AdvanceVariable 字段路径支持 |
| `drule-script` | 🆕 脚本引擎 SPI 模块 | ScriptEngine SPI 接口、ScriptContext、ScriptConfig、ScriptOutputDataType 类型转换、ScriptEngineProvider 服务发现 |
| `drule-jbpm` | BPMN 流程模块 | BPMN 2.0 流程编译、流程执行、节点监听、XML 转义、并行网关支持 |
| `drule-parse` | DRL 解析模块 | DRL 文件解析、语法树构建 |
| `drule-execute` | 执行模块 | 规则服务构建、会话管理、规则执行调度、监听器体系、变量加工处理器 |
`drule-spi` 是 SPI 实现聚合模块,当前包含:
| 模块 | 说明 | 核心功能 |
|------|------|----------|
| `drule-groovy` | 🆕 Groovy 脚本引擎 | Groovy 脚本执行、预编译缓存、通过 ServiceLoader 自动注册 |
### 数据流转
```
┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Java 对象 │ │ 可视化结构 │ │ DRL 文件 │ │ 规则执行 │
│ @ClassAnn │───▶│ DruleBlock │───▶│ 编译生成 │───▶│ RuleService │
│ │ │ │ │ │ │ │
└──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘
│ │ │ │
▼ ▼ ▼ ▼
TreeNode 规则条件/动作 DRL 内容 执行结果
```
## 📖 快速开始
### Maven 依赖
```xml
cn.ahaoweb.drule
drule-execute
2.1
```
如需使用脚本引擎(Groovy),额外引入:
```xml
cn.ahaoweb.drule.spi
drule-groovy
2.1
```
### 基础示例
#### 1. 定义规则对象
```java
@ClassAnn(name = "订单")
public class Order {
@FieldAnn(name = "订单金额")
private BigDecimal amount;
@FieldAnn(name = "订单状态")
private String status;
@FieldAnn(name = "用户信息")
private User user;
@FieldAnn(name = "收货地址")
private Address address;
// getter/setter...
}
@ClassAnn(name = "用户")
public class User {
@FieldAnn(name = "用户等级")
private String level;
@FieldAnn(name = "用户姓名")
private String name;
// getter/setter...
}
@ClassAnn(name = "地址")
public class Address {
@FieldAnn(name = "城市")
private String city;
// getter/setter...
}
@ClassAnn(name = "订单结果")
public class OrderResult {
@FieldAnn(name = "处理结果")
private String result;
@FieldAnn(name = "优惠金额")
private BigDecimal discount;
// getter/setter...
}
```
#### 2. 创建 DRL 规则服务(传统方式)
```java
// 方式一:使用 DruleServiceHelper(推荐)
RuleService ruleService = new DruleServiceHelper()
.identifier("order_rule")
.addContent(RuleType.RULE_BLOCK, drlContent)
.addConfig(RuleServiceConfiguration.EXECUTE_MODE.DEBUG)
.getRuleService();
// 方式二:使用 RuleServiceBuilder(🆕 2.0)
RuleService ruleService = new RuleServiceBuilder()
.identifier("order_rule")
.version("1.0.0")
.packageName("com.example.rules")
.addContent(RuleType.RULE_BLOCK, drlContent)
.addConfig(RuleServiceConfiguration.EXECUTE_MODE.DEBUG)
.build();
```
#### 3. 创建 BPMN 流程服务(🆕 2.0)
```java
// 构建 BPMN 流程
BpmnProcess process = new BpmnProcess("order_process", "订单处理流程");
// 添加开始节点
StartEventNode start = new StartEventNode("start", "开始");
process.addNode(start);
// 添加排他网关
ExclusiveGatewayNode gateway = new ExclusiveGatewayNode("gateway1", "金额判断");
process.addNode(gateway);
// 添加脚本任务
ScriptTaskNode highAmountTask = new ScriptTaskNode("task1", "大额订单处理");
highAmountTask.setScript("System.out.println(\"处理大额订单\");");
process.addNode(highAmountTask);
ScriptTaskNode lowAmountTask = new ScriptTaskNode("task2", "小额订单处理");
lowAmountTask.setScript("System.out.println(\"处理小额订单\");");
process.addNode(lowAmountTask);
// 添加结束节点
EndEventNode end = new EndEventNode("end", "结束");
process.addNode(end);
// 添加连接线
process.addSequenceFlow(new SequenceFlow("flow1", "start", "gateway1"));
process.addSequenceFlow(new SequenceFlow("flow2", "gateway1", "task1", "amount > 1000"));
process.addSequenceFlow(new SequenceFlow("flow3", "gateway1", "task2", "amount <= 1000"));
process.addSequenceFlow(new SequenceFlow("flow4", "task1", "end"));
process.addSequenceFlow(new SequenceFlow("flow5", "task2", "end"));
// 编译 BPMN 流程
BpmnProcessCompiler compiler = new BpmnProcessCompiler();
BpmnCompileResult result = compiler.compile(process);
// 创建 BPMN 规则服务
RuleService bpmnService = new DruleServiceHelper()
.identifier("bpmn_order_process")
.addContent(RuleType.BPMN, result.getBpmnXml())
.getRuleService();
```
#### 4. 执行规则/流程
```java
// 创建会话并执行
RuleSession session = ruleService.createSession();
// 准备输入数据
Order order = new Order();
order.setAmount(new BigDecimal("1500"));
order.setStatus("PENDING");
User user = new User();
user.setLevel("VIP");
user.setName("张三");
order.setUser(user);
Address address = new Address();
address.setCity("北京");
order.setAddress(address);
// 执行规则
OrderResult result = new OrderResult();
FactInfo factInfo = session.execute(order, result);
// 获取执行结果
System.out.println("处理结果: " + result.getResult());
System.out.println("优惠金额: " + result.getDiscount());
```
#### 5. 使用 3 层嵌套条件(🆕 2.0)
```java
// 构建 3 层嵌套条件结构
RuleWhen when = new RuleWhen();
// 超级组 1:订单金额和用户等级
RuleConditionSuperGroup superGroup1 = new RuleConditionSuperGroup();
superGroup1.setRelation("and");
// 条件组 1:订单金额
RuleConditionGroup group1 = new RuleConditionGroup();
group1.setRelation("and");
RuleCondition condition1 = new RuleCondition();
condition1.setPath("order.amount");
condition1.setOperator("gt");
condition1.setValue("1000");
group1.addCondition(condition1);
superGroup1.addGroup(group1);
// 条件组 2:用户等级
RuleConditionGroup group2 = new RuleConditionGroup();
group2.setRelation("and");
RuleCondition condition2 = new RuleCondition();
condition2.setPath("order.user.level");
condition2.setOperator("eq");
condition2.setValue("VIP");
group2.addCondition(condition2);
superGroup1.addGroup(group2);
when.addSuperGroup(superGroup1);
// 编译为 DRL
DefaultDruleCompile compiler = new DefaultDruleCompile(
Arrays.asList(druleBlock),
TreeNode.treeNode(Order.class),
TreeNode.treeNode(OrderResult.class)
);
DruleCompileStructure compileResult = compiler.compile();
String drl = compileResult.toDrl();
// 生成的 DRL 代码:
// $order: Order(amount > 1000)
// $user: User(level == "VIP") from $order.user
```
## 📖 详细使用说明
### 🆕 2.1 版本新特性
#### 1. 脚本引擎 SPI 架构(drule-script + drule-spi)
2.1 版本引入可插拔的脚本引擎架构,支持在规则执行前通过脚本对变量进行加工处理。
**架构设计**:
- `drule-script`(drule-core 子模块):定义 SPI 接口层(`ScriptEngine`、`ScriptContext`、`ScriptConfig`)
- `drule-spi/drule-groovy`(顶层模块):Groovy 脚本引擎实现,通过 Java `ServiceLoader` 自动注册
**核心类**:
| 类名 | 说明 |
|------|------|
| `ScriptEngine` | SPI 接口,定义 `eval()`、`compile()`、`getLanguage()` |
| `ScriptContext` | 脚本执行上下文,封装脚本代码、变量绑定和预编译产物 |
| `ScriptConfig` | 单个脚本配置(脚本内容、输出变量 key、数据类型、排序号) |
| `ScriptEngineProvider` | 引擎提供者,通过 ServiceLoader 加载并缓存所有实现 |
| `ScriptOutputDataType` | 输出数据类型枚举,支持 String/Integer/Long/BigDecimal/Boolean/Double/Float/Object/List/Map |
| `GroovyScriptEngine` | Groovy 实现,支持预编译缓存 |
**使用示例**:
```java
// 1. 配置脚本
ScriptConfig config = new ScriptConfig();
config.setProcessId("script_001");
config.setProcessName("计算年龄段");
config.setScriptLanguage("groovy");
config.setScriptContent("return input.age >= 18 ? 'adult' : 'minor'");
config.setOutputKey("ageGroup");
config.setOutputDataType("java.lang.String");
config.setSortOrder(1);
// 2. 创建变量加工处理器
VariableProcessor processor = new VariableProcessor(Arrays.asList(config));
// 3. 作为前置处理器添加到规则会话
RuleSession session = ruleService.createSession()
.addPreExecuteHandler(processor);
// 4. 执行规则 - 脚本会在规则执行前自动运行
// 脚本返回值写入 input.advanceVariables["ageGroup"]
session.execute(input, output);
```
**扩展新语言**:
实现 `ScriptEngine` 接口并通过 SPI 注册即可:
```java
// 1. 实现接口
public class JavaScriptEngine implements ScriptEngine {
@Override
public Object eval(ScriptContext context) { /* ... */ }
@Override
public String getLanguage() { return "javascript"; }
}
// 2. 注册 SPI
// META-INF/services/cn.ahaoweb.drule.core.script.ScriptEngine
// cn.example.JavaScriptEngine
```
#### 2. 变量加工处理器(VariableProcessor)
`VariableProcessor` 实现 `PreExecuteHandler` 接口,在规则执行前按 `sortOrder` 升序依次执行脚本配置,将脚本返回值写入入参对象的 `advanceVariables` Map 中。
**核心特性**:
- 构造时预编译所有脚本(提升运行时性能)
- 按 `sortOrder` 升序执行,支持脚本间依赖
- 自动类型转换(通过 `ScriptOutputDataType`)
- 入参对象必须继承 `RuleBase`(提供 `advanceVariables` Map)
**执行流程**:
```
VariableProcessor.preHandler()
├── 遍历 scriptConfigs(按 sortOrder 升序)
│ ├── ScriptEngineProvider.getEngine(language)
│ ├── buildBindings(input, config) ← 可覆盖
│ ├── engine.eval(context)
│ └── writeToAdvanceVariables(input, key, dataType, result) ← 可覆盖
└── 完成,advanceVariables 已填充
```
#### 3. 并行网关支持(ParallelGateway)
BPMN 流程新增并行网关节点,支持流程的并行分支和聚合。
**节点类型**:
- `ParallelGatewayNode`(Diverging):分支节点,一入多出,所有出边同时触发,出边无条件表达式
- `ParallelGatewayNode`(Converging):聚合节点,多入一出,等待所有分支完成后继续
**使用示例**:
```java
// 创建并行分支
ParallelGatewayNode fork = new ParallelGatewayNode();
fork.setId("fork1");
fork.setName("并行分支");
fork.setGatewayDirection(ParallelGatewayNode.DIRECTION_DIVERGING);
// 创建并行聚合
ParallelGatewayNode join = new ParallelGatewayNode();
join.setId("join1");
join.setName("并行聚合");
join.setNodeType(BpmnNodeType.PARALLEL_JOIN);
join.setGatewayDirection(ParallelGatewayNode.DIRECTION_CONVERGING);
// 添加到流程
process.addNode(fork);
process.addNode(join);
// 连接线(并行分支的出边不需要条件表达式)
process.addSequenceFlow(new SequenceFlow("flow1", "fork1", "task1"));
process.addSequenceFlow(new SequenceFlow("flow2", "fork1", "task2"));
process.addSequenceFlow(new SequenceFlow("flow3", "task1", "join1"));
process.addSequenceFlow(new SequenceFlow("flow4", "task2", "join1"));
```
**编译校验规则**:
- 并行分支节点:出边至少 2 条
- 并行聚合节点:入边至少 2 条,出边必须 1 条
#### 4. AdvanceVariable 字段类型与数据类型支持
条件编译新增 `AdvanceVariable`(加工变量)字段类型,支持在 DRL 表达式中引用 `advanceVariables` Map 中的变量。
**核心改动**:
- `ConditionFieldTypeEnum` 新增 `AdvanceVariable` 枚举值
- `ConditionExpression` 新增 `path` 字段(如 `advanceVariables.get("ageGroup")`)
- `RuleFieldInfo` 新增 `dataType` 字段,支持类型转换
- `Operator` 新增 `resolveFieldExpression()` 方法,根据字段类型生成不同的 DRL 表达式
**DRL 表达式生成示例**:
```java
// 普通字段
// fieldCode: age → DRL: age == 18
// AdvanceVariable 字段(无类型转换)
// path: advanceVariables.get("ageGroup") → DRL: advanceVariables.get("ageGroup") == "adult"
// AdvanceVariable 字段(有类型转换)
// path: advanceVariables.get("score"), dataType: java.lang.Integer
// → DRL: ((java.lang.Integer) advanceVariables.get("score")) > 80
```
#### 5. 其他改进
- **FactInfo 泛型约束**:入参类型 `I` 增加 `extends RuleBase` 约束,确保入参对象具备 `advanceVariables` 能力
- **FactInfo 新增 `ruleIdentifier` 字段**:用于追踪和缓存绑定,`RuleServiceScheduler` 执行时自动设置
- **规则会话资源清理**:`AbstractRuleSession.doExecute()` 改用 `try-finally` 确保 `session.destroy()` 始终执行
- **JsonUtil 工具类**:基于 Jackson 的 JSON 序列化/反序列化工具,规则引擎内部统一使用
- **测试框架升级**:drule-execute 模块升级到 JUnit 5 + Mockito 4.11(支持 `mockStatic`)
### 🆕 2.0 版本新特性
#### 1. 3 层嵌套条件支持
2.0 版本支持更复杂的条件结构:SuperGroup(超级组)→ ConditionGroup(条件组)→ Condition(条件)
**场景 1:所有条件在根对象**
```java
// 输入条件
order.amount > 100 && order.status == "PAID"
// 生成的 DRL
$order: Order(amount > 100 && status == "PAID")
```
**场景 2:条件分布在根对象和子对象**
```java
// 输入条件
- order.amount > 100
- order.user.level == "VIP"
// 生成的 DRL
$order: Order(amount > 100)
$user: User(level == "VIP") from $order.user
```
**场景 3:超级组内条件跨层级(归属根对象)**
```java
// 输入条件(同一超级组内)
order.amount > 100 && order.user.level == "VIP"
// 生成的 DRL(使用根对象)
$order: Order(amount > 100 && user.level == "VIP")
```
**场景 4:多个子对象独立**
```java
// 输入条件
- order.amount > 100
- order.user.level == "VIP"
- order.address.city == "北京"
// 生成的 DRL
$order: Order(amount > 100)
$user: User(level == "VIP") from $order.user
$address: Address(city == "北京") from $order.address
```
#### 2. BPMN 流程支持
新增 `drule-jbpm` 模块,支持 BPMN 2.0 流程的编译和执行。
**支持的节点类型**:
- StartEvent - 开始事件
- EndEvent - 结束事件
- ExclusiveGateway - 排他网关
- ParallelGateway - 🆕 并行网关(分支/聚合)
- ScriptTask - 脚本任务
- SequenceFlow - 连接线
**使用示例**:
```java
// 创建 BPMN 流程
BpmnProcess process = new BpmnProcess("order_process", "订单处理流程");
// 添加开始节点
StartEventNode start = new StartEventNode("start", "开始");
process.addNode(start);
// 添加排他网关
ExclusiveGatewayNode gateway = new ExclusiveGatewayNode("gateway1", "金额判断");
process.addNode(gateway);
// 添加脚本任务
ScriptTaskNode task1 = new ScriptTaskNode("task1", "大额订单处理");
task1.setScript("System.out.println(\"处理大额订单\");");
process.addNode(task1);
// 添加连接线
process.addSequenceFlow(new SequenceFlow("flow1", start.getId(), gateway.getId()));
process.addSequenceFlow(new SequenceFlow("flow2", gateway.getId(), task1.getId(), "amount > 1000"));
// 编译 BPMN 流程
BpmnProcessCompiler compiler = new BpmnProcessCompiler();
BpmnCompileResult result = compiler.compile(process);
// 创建规则服务并执行
RuleService ruleService = new DruleServiceHelper()
.identifier("bpmn_test")
.addContent(RuleType.BPMN, result.getBpmnXml())
.getRuleService();
RuleSession session = ruleService.createSession();
session.execute(orderInput, orderOutput);
```
#### 3. 性能优化 - TreeNode 缓存
新增 LRU 缓存机制,显著提升编译性能。
```java
// 缓存配置(默认已启用)
RuleModelConfiguration.setCacheEnabled(true);
RuleModelConfiguration.setCacheCapacity(1000);
// TreeNode 查找会自动使用缓存
TreeNode node = treeNode.find("order.user.name");
```
**性能提升**:
- 减少重复查找
- 降低 CPU 消耗
- 提升编译速度
#### 4. 编译器架构升级
**新增核心类**:
- `ObjectHierarchyPartitioner` - 对象层次划分器
- `DrlCodeGenerator` - DRL 代码生成器
- `ConditionModelAdapter` - 条件模型适配器
- `ExpressionCompiler` - 表达式编译器体系
**架构对比**:
```
重构前:
DefaultDruleCompile (800+ lines)
└── compileWhen (400+ lines) - 臃肿的单一方法
重构后:
DefaultDruleCompile (精简)
├── ObjectHierarchyPartitioner - 对象层次划分
├── DrlCodeGenerator - DRL 代码生成
├── ConditionModelAdapter - 统一模型转换
└── compileWhen (10 lines) - 路由方法
```
---
### 1. drule-models 模块
#### 1.1 TreeNode - 对象结构树
`TreeNode` 类用于构建类型(`Class`)结构树,提供了构建树节点、获取节点信息、判断节点类型以及根据路径查找节点等功能。
**核心方法**:`TreeNode.treeNode(Class> clazz)`
**使用示例**:
```java
// 设置默认的配置信息
RuleModelConfiguration.setChildDepth(2);
// 扫描规则对象,转换为树形结构
TreeNode treeNode = TreeNode.treeNode(TestObj.class);
System.out.println(treeNode);
// 通过路径获取对应节点
System.out.println(treeNode.find("testObj.treeNodes.cesu"));
```
> ⚠️ 注意:所扫描的 Class 必须使用 `@ClassAnn` 注解标注。
### 2. drule-compile 模块
#### 2.1 DefaultDruleCompile - 规则编译器
`DefaultDruleCompile` 是默认规则编译器,用于将结构化规则对象编译为 DRL 文件。
**核心方法**:
| 方法 | 功能 | 参数 | 返回值 |
|------|------|------|--------|
| `addFunction(DruleFunction)` | 添加函数 | 函数对象 | boolean |
| `addImport(String)` | 添加包/类引入 | 包/类名 | void |
| `addGlobal(String, String)` | 添加全局变量 | 标识符, 类型 | void |
| `compile()` | 编译规则 | - | DruleCompileStructure |
| `compileRule(DruleBlock)` | 编译单个规则块 | 规则块 | String |
| `validateRules()` | 校验规则结构 | - | ValidateResult |
| `compileWhen3Layer()` | 编译 3 层嵌套条件 | 规则条件 | String |
| `compileWhen2Layer()` | 编译 2 层条件 | 规则条件 | String |
**使用示例**:
```java
// 配置好规则块集合
List rules = ...;
// 入参对象的树形结构
TreeNode inNode = TreeNode.treeNode(TestIn.class);
// 出参对象的树形结构
TreeNode outNode = TreeNode.treeNode(TestOut.class);
// 构建默认编译器
DefaultDruleCompile compiler = new DefaultDruleCompile(rules, inNode, outNode);
// 校验规则结构
ValidateResult validate = compiler.validateRules();
if (validate.isSuccess()) {
// 执行编译
DruleCompileStructure result = compiler.compile();
// 输出最终编译的 DRL 内容
System.out.println(result.toDrl());
}
```
#### 2.2 ObjectHierarchyPartitioner - 对象层次划分器(🆕 2.0)
`ObjectHierarchyPartitioner` 用于将条件按对象层次进行划分,支持 3 层和 2 层格式。
**核心规则**:
1. 超级组内条件属于同一子对象 → 归属该子对象
2. 超级组内条件跨不同层级 → 归属根对象
3. 超级组内条件跨不同子对象 → 归属根对象
4. 超级组间 or 关系且跨对象 → 抛出异常
**使用示例**:
```java
// 创建划分器
ObjectHierarchyPartitioner partitioner = new ObjectHierarchyPartitioner(inNode);
// 3 层格式划分
Map> result =
partitioner.partition3Layer(superGroups);
// 遍历结果
for (Map.Entry> entry : result.entrySet()) {
String objectPath = entry.getKey(); // 对象路径
List groups = entry.getValue(); // 该对象的条件组
System.out.println("对象: " + objectPath + ", 条件数: " + groups.size());
}
```
#### 2.3 DrlCodeGenerator - DRL 代码生成器(🆕 2.0)
`DrlCodeGenerator` 提供统一的 DRL 代码生成方法。
**核心方法**:
```java
// 生成根对象模式匹配
String pattern = DrlCodeGenerator.generateRootObjectPattern(
objectName, objectType, conditionExpression);
// 生成子对象模式匹配(from 语法)
String pattern = DrlCodeGenerator.generateChildObjectPattern(
objectName, objectType, conditionExpression, parentPath);
// 生成空对象模式匹配
String pattern = DrlCodeGenerator.generateEmptyObjectPattern(
objectName, objectType);
```
#### 2.4 DruleChineseTranslation - 中文转译器
`DruleChineseTranslation` 用于将规则块转译为中文文本,便于业务人员理解。
**使用示例**:
```java
// 构建中文转译器
ChineseTranslation translator = DruleChineseTranslation.buildTranslation(rules, inNode, outNode);
// 方式一:获取转译后的规则结构体集合
List translatedRules = translator.translateRules();
// 方式二:获取转译后的规则文本内容
String translatedText = translator.generateText();
```
#### 2.5 DiffHandleUtils - 差异对比工具
用于对比规则内容的差异,支持生成可视化 HTML 文件。
```java
// 需要对比的内容
List oldContent = ...;
List newContent = ...;
// 执行对比
List diffList = DiffHandleUtils.diffList(oldContent, newContent, "原内容", "新内容");
// 生成可视化 HTML 文件
DiffHandleUtils.generateDiffHtml(diffList, "/path/to/output.html");
```
#### 2.6 FieldUsedLocator - 字段定位器
用于定位出入参字段被使用在哪些规则块(`DruleBlock`)中。
```java
// 使用默认的字段匹配器
List result = FieldUsedLocator.simpleLocate(druleBlockList, nodes);
// 使用自定义字段匹配器
List result = FieldUsedLocator.locate(druleBlockList, nodes, customMatcher);
```
### 3. drule-jbpm 模块(🆕 2.0)
#### 3.1 BpmnProcessCompiler - BPMN 流程编译器
`BpmnProcessCompiler` 用于将 BPMN 流程模型编译为 jBPM 可执行的 XML 格式。
**支持的节点类型**:
| 节点类型 | 类名 | 说明 |
|---------|------|------|
| 开始事件 | `StartEventNode` | 流程的起点 |
| 结束事件 | `EndEventNode` | 流程的终点 |
| 排他网关 | `ExclusiveGatewayNode` | 条件分支,只能选择一条路径 |
| 并行网关 | `ParallelGatewayNode` | 🆕 并行分支/聚合,所有分支同时执行 |
| 脚本任务 | `ScriptTaskNode` | 执行 Java 脚本代码 |
| 连接线 | `SequenceFlow` | 连接节点,可设置条件 |
**使用示例**:
```java
// 1. 创建 BPMN 流程
BpmnProcess process = new BpmnProcess("order_check", "订单审核流程");
// 2. 添加开始节点
StartEventNode start = new StartEventNode("start", "开始");
process.addNode(start);
// 3. 添加排他网关
ExclusiveGatewayNode gateway = new ExclusiveGatewayNode("gateway1", "金额判断");
process.addNode(gateway);
// 4. 添加脚本任务
ScriptTaskNode highAmountTask = new ScriptTaskNode("task1", "大额订单处理");
highAmountTask.setScript("System.out.println(\"处理大额订单: \" + order.getAmount());");
highAmountTask.setScriptFormat("java");
process.addNode(highAmountTask);
ScriptTaskNode lowAmountTask = new ScriptTaskNode("task2", "小额订单处理");
lowAmountTask.setScript("System.out.println(\"处理小额订单: \" + order.getAmount());");
process.addNode(lowAmountTask);
// 5. 添加结束节点
EndEventNode end = new EndEventNode("end", "结束");
process.addNode(end);
// 6. 添加连接线
process.addSequenceFlow(new SequenceFlow("flow1", "start", "gateway1"));
process.addSequenceFlow(new SequenceFlow("flow2", "gateway1", "task1", "order.amount > 1000"));
process.addSequenceFlow(new SequenceFlow("flow3", "gateway1", "task2", "order.amount <= 1000"));
process.addSequenceFlow(new SequenceFlow("flow4", "task1", "end"));
process.addSequenceFlow(new SequenceFlow("flow5", "task2", "end"));
// 7. 编译流程
BpmnProcessCompiler compiler = new BpmnProcessCompiler();
BpmnCompileResult result = compiler.compile(process);
// 8. 获取 BPMN XML
String bpmnXml = result.getBpmnXml();
System.out.println(bpmnXml);
```
#### 3.2 DroolsRuleExpressionCompiler - Drools 表达式编译器
`DroolsRuleExpressionCompiler` 用于将规则条件编译为 Drools 表达式,供 BPMN 网关使用。
**使用示例**:
```java
// 创建规则条件
RuleWhen when = new RuleWhen();
// ... 配置条件
// 编译为 Drools 表达式
DroolsRuleExpressionCompiler compiler = new DroolsRuleExpressionCompiler(inNode);
String expression = compiler.compile(when);
// 在网关中使用
ExclusiveGatewayNode gateway = new ExclusiveGatewayNode("gateway1", "条件判断");
SequenceFlow flow = new SequenceFlow("flow1", "gateway1", "task1", expression);
```
#### 3.3 BpmnChineseTranslation - BPMN 中文翻译
`BpmnChineseTranslation` 用于将 BPMN 流程转译为中文文本。
**使用示例**:
```java
// 创建翻译器
BpmnChineseTranslation translator = new BpmnChineseTranslation(process);
// 生成中文描述
String chineseText = translator.translate();
System.out.println(chineseText);
// 输出示例:
// 流程:订单审核流程
// 1. 开始
// 2. 判断:金额判断
// - 如果 订单金额 > 1000,则执行:大额订单处理
// - 如果 订单金额 <= 1000,则执行:小额订单处理
// 3. 结束
```
#### 3.4 XmlEscapeUtil - XML 转义工具
`XmlEscapeUtil` 用于处理 XML 特殊字符的转义和反转义。
**使用示例**:
```java
// 转义 XML 特殊字符
String escaped = XmlEscapeUtil.escape("amount > 100 && status == \"PAID\"");
// 输出: amount > 100 && status == "PAID"
// 反转义
String unescaped = XmlEscapeUtil.unescape(escaped);
// 输出: amount > 100 && status == "PAID"
// 转义正则表达式
String regexEscaped = XmlEscapeUtil.escapeRegex("name matches \"ja.*\"");
```
#### 3.5 BPMN 与规则服务集成
**完整示例**:
```java
// 1. 编译 BPMN 流程
BpmnProcessCompiler compiler = new BpmnProcessCompiler();
BpmnCompileResult result = compiler.compile(process);
// 2. 创建规则服务
RuleService ruleService = new DruleServiceHelper()
.identifier("bpmn_order_process")
.addContent(RuleType.BPMN, result.getBpmnXml())
.addConfig(RuleServiceConfiguration.EXECUTE_MODE.DEBUG)
.getRuleService();
// 3. 创建会话并执行
RuleSession session = ruleService.createSession();
// 4. 准备输入数据
Order order = new Order();
order.setAmount(1500);
order.setStatus("PENDING");
// 5. 执行流程
FactInfo factInfo = session.execute(order, new OrderResult());
// 6. 获取执行结果
OrderResult result = (OrderResult) factInfo.getOutput();
System.out.println("流程执行结果: " + result);
```
### 4. drule-parse 模块
#### 4.1 DruleContentParser - DRL 解析器
`DruleContentParser` 用于解析 DRL 文本内容,将其转换为结构化的 `DrlFile` 对象。
**支持的 DRL 元素类型**:
| 类型 | 说明 | 示例 |
|------|------|------|
| `PACKAGE` | 包声明 | `package com.example;` |
| `IMPORT` | 导入声明 | `import com.example.Model;` |
| `GLOBAL` | 全局变量 | `global Logger log;` |
| `RULE` | 规则定义 | `rule "test" when ... then ... end` |
| `FUNCTION` | 函数定义 | `function void test() { ... }` |
| `DECLARE` | 类型声明 | `declare Person ... end` |
| `QUERY` | 查询定义 | `query "findPerson" ... end` |
| `COMMENT` | 注释 | `// 单行注释` 或 `/* 多行注释 */` |
**使用示例**:
```java
// 解析 DRL 文本
DrlFile drlFile = DruleContentParser.parseDrl(drlText);
drlFile.parse();
// 获取所有规则
List rules = drlFile.getDrlTrees(DrlType.RULE);
// 获取所有导入
List imports = drlFile.getDrlTrees(DrlType.IMPORT);
```
### 5. drule-execute 模块
#### 5.1 RuleService - 规则服务
`RuleService` 是规则服务的核心接口,用于配置和构建规则会话。
**创建方式一:构造器方法**
```java
RuleService ruleService = new RuleServiceImpl("id01", "1.0.0", "cn.ahaoweb", null)
// 添加规则内容(必要)
.addContent(RuleType.RULE_BLOCK, drl)
// 修改配置(可选)
.addConfig(RuleServiceConfiguration.RULE_CONTENT_CACHE.PROPERTY_NAME,
RuleServiceConfiguration.RULE_CONTENT_CACHE.OPEN.value())
// 事实对象类型选择器(可选)
.factClassSelector(new FactClassSelector() {
@Override
public Class inType() { return TestIn.class; }
@Override
public Class outType() { return TestOut.class; }
})
// 初始化(必要)
.init();
```
**创建方式二:DruleServiceHelper(推荐)**
```java
RuleService ruleService = new DruleServiceHelper()
.identifier("test_rule")
.addContent(RuleType.RULE_BLOCK, drl)
.addConfig(RuleServiceConfiguration.RULE_CONTENT_CACHE.CLOSE)
.addConfig(RuleServiceConfiguration.EXECUTE_MODE.DEBUG)
.getRuleService();
```
#### 5.2 RuleSession - 规则会话
`RuleSession` 用于执行规则,支持添加前置/后置处理器、监听器等。
**执行流程**:
```
┌─────────────────────────────────────────────────────────────────────────┐
│ RuleSession 执行流程 │
├─────────────────────────────────────────────────────────────────────────┤
│ 1. enter() ──▶ 可扩展入口点 │
│ 2. preExecuteHandlers ──▶ 执行前置处理器 │
│ 3. afterPreHandlers() ──▶ 可扩展点 │
│ 4. listeners + 执行规则 ──▶ 添加监听器并执行规则 │
│ 5. afterExecuted() ──▶ 可扩展点 │
│ 6. postExecuteHandlers ──▶ 执行后置处理器 │
│ 7. afterPostHandlers() ──▶ 可扩展点 │
│ 8. destroy() ──▶ 销毁会话 │
│ 9. exit() ──▶ 可扩展出口点 │
└─────────────────────────────────────────────────────────────────────────┘
```
**使用示例**:
```java
// 创建规则会话
RuleSession session = ruleService.createSession()
// 添加前置处理器
.addPreExecuteHandler(new PreExecuteHandler() {
@Override
public void preHandler(FactInfo factInfo) {
TestIn input = factInfo.getInput();
input.setAge(10);
System.out.println("前置处理器:" + input);
}
})
// 添加后置处理器
.addPostExecuteHandler(new PostExecuteHandler() {
@Override
public void postHandler(FactInfo factInfo) {
TestOut output = (TestOut) factInfo.getOutput();
System.out.println("后置处理器:" + output);
}
});
// 执行方式一:使用 FactInfo
FactInfo factInfo = FactInfo.FactInfoBuilder.builder()
.input(new TestIn())
.inputClass(TestIn.class)
.inputName("testIn")
.outputClass(TestOut.class)
.build();
session.execute(factInfo);
// 执行方式二:直接传入对象
FactInfo result = session.execute(new TestIn(), new TestOut());
```
#### 5.3 RuleServiceScheduler - 规则服务调度器
`RuleServiceScheduler` 提供统一管理规则服务的功能,支持通过标识符或入参对象类型执行规则。
**使用方式一:通用流程**
```java
// 1. 构建调度器
RuleServiceScheduler scheduler = new RuleServiceScheduler();
// 2. 添加规则服务
scheduler.addService(ruleService1);
scheduler.addService("test2", ruleService2);
// 3. 配置会话(可选)
RuleSession session = scheduler.getRuleSession("test1");
session.addPreExecuteHandler(...);
// 4. 执行规则
scheduler.execute("test1", new TestIn()); // 通过标识符
scheduler.execute(new TestIn()); // 通过入参类型(需确保一一对应)
```
**使用方式二:动态流程**
```java
// 构建调度器,配置 RuleServiceConstructor
RuleServiceScheduler scheduler = new RuleServiceScheduler(new RuleServiceConstructor() {
@Override
public RuleService getRuleService(String identifier) {
// 可从数据库等动态获取规则服务
if ("test1".equals(identifier)) {
return buildRuleService1();
}
return null;
}
});
// 直接执行,调度器会自动获取规则服务
scheduler.execute("test1", new TestIn());
```
#### 5.4 AfterCreateSessionCallback - 会话创建回调
在规则会话创建后提供扩展点,允许执行自定义逻辑。
```java
RuleService ruleService = new DruleServiceHelper()
.identifier("test")
.addContent(RuleType.RULE_BLOCK, drl)
.afterCreateSessionCallback(session -> {
// 在会话创建后添加处理器
session.addPreExecuteHandler(new PreExecuteHandler() {
@Override
public void preHandler(FactInfo factInfo) {
log.info("执行前处理:{}", factInfo);
}
});
return session;
})
.getRuleService();
```
## 📝 配置说明
### 规则条件运算符
| 运算符 | 符号 | 说明 | 示例 |
|--------|------|------|------|
| `eq` | `==` | 等于 | `name == "jack"` |
| `neq` | `!=` | 不等于 | `name != "jack"` |
| `lt` | `<` | 小于 | `age < 18` |
| `lte` | `<=` | 小于等于 | `age <= 18` |
| `gt` | `>` | 大于 | `age > 18` |
| `gte` | `>=` | 大于等于 | `age >= 18` |
| `left_contains` | `contains` | 包含(左) | `name contains "jack"` |
| `right_contains` | `contains` | 包含(右) | `"jack" contains name` |
| `not_left_contains` | `not contains` | 不包含(左) | `name not contains "jack"` |
| `not_right_contains` | `not contains` | 不包含(右) | `"jack" not contains name` |
| `in` | `in` | 存在于 | `name in ("jack", "mary")` |
| `not_in` | `not in` | 不存在于 | `name not in ("jack", "mary")` |
| `matches` | `matches` | 正则匹配 | `name matches "ja.*"` |
| `not_matches` | `not matches` | 正则不匹配 | `name not matches "ja.*"` |
### 运算符详细说明
#### eq、neq
等价于 Java 中的 `equals()` 和 `!equals()`。
#### lt、lte、gt、gte
关系运算 `<`、`<=`、`>`、`>=`。
#### left_contains、right_contains
- **包含(左)**:参数字段在左侧,如 `name contains "jack"`
- **包含(右)**:参数字段在右侧,如 `"jack" contains name`
- 支持 List 和字符串类型
#### in、not_in
相当于 SQL 中的 `IN` 操作符,用于检查某个值是否包含在给定的多个可能值中。
#### matches、not_matches
与指定的 Java 正则表达式匹配或不匹配。
## 🎋 版本历史
| 版本 | 主要更新 |
|------|----------|
| **release-2.1** | 新增 `drule-script` 脚本引擎 SPI 模块及 `drule-groovy` 实现;新增 `VariableProcessor` 变量加工处理器;新增并行网关 `ParallelGatewayNode`;新增 `AdvanceVariable` 字段类型;测试框架升级至 JUnit 5 + Mockito 4.11(174 个测试全部通过) |
| **release-2.0** | 新增 `drule-jbpm` BPMN 流程模块;编译器架构重构,新增 `ObjectHierarchyPartitioner`、`DrlCodeGenerator`;支持 3 层嵌套条件;新增 TreeNode LRU 缓存;新增 20+ 测试类,测试覆盖率 100% |
| **release-1.7** | 新增 `drule-parse` 模块,支持 DRL 文件解析和语法树构建 |
| **release-1.6** | 1. 新增字段定位器 `FieldUsedLocator`
2. 新增规则执行异常处理器 `RuleExecuteExceptionHandler`
3. 新增会话创建回调 `AfterCreateSessionCallback` |
| **release-1.5** | 1. 新增 8 种条件运算符
2. 规则服务调度器支持通过入参对象执行规则 |
| **release-1.4** | 1. 新增规则服务调度器 `RuleServiceScheduler`
2. 新增事实对象类型选择器 `factClassSelector` |
| **release-1.3** | 1. 新增中文转译器 `ChineseTranslation`
2. 新增文本差异对比工具 `DiffHandleUtils`
3. 修复节点类型中布尔类型问题 |
| **release-1.2** | 1. 新增规则校验方法 `validateRules`
2. 根据类型选择不同的值处理逻辑 |
| **release-1.1** | 新增 `drule-execute` 模块,统一执行框架 |
| **release-1.0** | 初版发布,支持规则对象配置和规则编译功能 |
---
## 🎉 2.1 版本重大更新
### 脚本引擎 SPI 架构
2.1 版本引入可插拔的脚本引擎架构,实现规则执行前的变量加工能力。
#### 1. 架构设计
**分层设计**:
```
drule-core/drule-script(SPI 接口层)
├── ScriptEngine - SPI 接口:eval() / compile() / getLanguage()
├── ScriptContext - 执行上下文:脚本代码 + 变量绑定 + 预编译产物
├── ScriptConfig - 脚本配置:语言、内容、输出 key、数据类型、排序号
├── ScriptEngineProvider - 引擎提供者:ServiceLoader 加载 + 缓存
├── ScriptOutputDataType - 输出类型枚举:10 种类型转换
└── exception/ - 异常体系:ScriptCompileException / ScriptExecuteException
drule-spi/drule-groovy(SPI 实现层)
└── GroovyScriptEngine - Groovy 实现:预编译 + Binding 注入 + 异常封装
```
**设计原则**:
- 接口与实现分离,核心模块不依赖具体脚本语言
- 通过 Java ServiceLoader 自动发现和注册引擎
- 预编译缓存机制,避免重复编译开销
#### 2. VariableProcessor 变量加工处理器
**核心流程**:
```
构造阶段:
scriptConfigs → 按 sortOrder 排序 → 逐个预编译 → 缓存编译产物
执行阶段(preHandler):
遍历 scriptConfigs
→ 获取 ScriptEngine
→ 构建 bindings(input 对象)
→ 创建 ScriptContext(含预编译产物)
→ engine.eval(context)
→ 类型转换(ScriptOutputDataType)
→ 写入 input.advanceVariables[outputKey]
```
**扩展点**:
- `buildBindings()` - 可覆盖以注入额外变量
- `writeToAdvanceVariables()` - 可覆盖以自定义写入逻辑
#### 3. AdvanceVariable 条件编译
**新增字段类型**:`ConditionFieldTypeEnum.AdvanceVariable`
**DRL 表达式生成规则**:
- 普通字段:直接使用 `fieldCode`(如 `age`)
- AdvanceVariable 无类型:使用 `path`(如 `advanceVariables.get("ageGroup")`)
- AdvanceVariable 有类型:添加类型转换(如 `((java.lang.Integer) advanceVariables.get("score"))`)
- 非 `java.lang.*` 和 `java.util.*` 的类型自动添加 import
### 并行网关支持
#### ParallelGatewayNode
**节点模型**:
- `DIRECTION_DIVERGING`(分支):一入多出,所有出边同时触发
- `DIRECTION_CONVERGING`(聚合):多入一出,等待所有分支完成
**编译校验**:
- 分支节点出边 ≥ 2
- 聚合节点入边 ≥ 2,出边 = 1
- 分支节点的出边自动跳过条件表达式生成
**生成的 BPMN XML**:
```xml
flow_in
flow_out1
flow_out2
```
### 执行引擎改进
#### FactInfo 泛型约束
入参类型 `I` 增加 `extends RuleBase` 约束,确保所有入参对象具备 `advanceVariables` Map。
**影响范围**:
- `FactInfo`
- `RuleSession.execute()`
- `RuleServiceScheduler.execute()`
- `PreExecuteHandler`
- `PostExecuteHandler`
#### 资源清理改进
`AbstractRuleSession.doExecute()` 中 `session.destroy()` 改用 `try-finally` 包裹,确保异常时也能正确释放 KieSession 资源。
### 新增测试
| 测试类 | 模块 | 测试内容 |
|--------|------|----------|
| `VariableProcessorTest` | drule-execute | 变量加工处理器(7 个测试用例) |
| `ParallelGatewayNodeTest` | drule-jbpm | 并行网关节点(6 个测试用例) |
| `ScriptContextTest` | drule-script | 脚本上下文(4 个测试用例) |
| `ScriptEngineProviderTest` | drule-script | 引擎提供者(3 个测试用例) |
| `GroovyScriptEngineTest` | drule-groovy | Groovy 引擎(4 个测试用例) |
### Bug 修复与代码质量
| 类别 | 修复内容 |
|------|----------|
| 废弃 API | `FactInfo.getOutputInstance()` 和 `GroovyScriptEngine.eval()` 中 `newInstance()` 替换为 `getDeclaredConstructor().newInstance()` |
| NPE 修复 | `ObjectHierarchyPartitioner.root` 为 null 时的 NPE;`Operator.resolveFieldExpression()` 未判断 `fieldInfo` 为 null |
| XML 安全 | `BpmnProcessCompiler.compileParallelGateway()` 中 `id`/`name`/`gatewayDirection` 属性改用 `XmlEscapeUtil.escapeXml()` 转义 |
| 异常处理 | `ScriptOutputDataType` 数值转换失败包装为 `ScriptExecuteException` 并附带原始值和目标类型上下文 |
| 健壮性 | `ScriptEngineProvider` SPI 加载异常单独捕获,单个引擎失败 warn 日志跳过;`VariableProcessor.writeToAdvanceVariables()` 校验 outputKey 不为空 |
| 代码规范 | `ConditionFieldTypeEnum.chinese` 改为 `final`;`ScriptConfig` 改用 `@Data`;`JsonUtil` 新增专属 `JsonException` |
| 构建规范 | 根 pom 移除 PowerMock 全局依赖;统一配置 `maven-surefire-plugin 3.1.2`;`drule-compile`/`drule-jbpm`/`drule-models` 补充 JUnit 5 测试依赖 |
| 测试迁移 | 20 个测试文件从 JUnit 4 全量迁移到 JUnit 5,断言参数顺序修正,`@Test(expected=...)` 迁移为 `assertThrows` |
### 统计数据
| 指标 | 数值 |
|------|------|
| 提交数 | 9 |
| 变更文件数 | 51 |
| 新增代码 | +1,594 行 |
| 删除代码 | -65 行 |
| 新增模块 | 3(drule-script、drule-spi、drule-groovy) |
| 新增测试类 | 5 |
| 新增测试用例 | 24 |
| 全量测试通过 | 174 个(0 失败) |
| Bug 修复 | 17 项(含废弃 API、NPE、XML 注入、资源泄漏等) |
---
## 📄 License
[MIT License](LICENSE)