如何在RuoYi-Cloud中构建动态规则引擎:从原理到实践
2026-04-16 08:12:16作者:贡沫苏Truman
RuoYi-Cloud作为基于Spring Cloud & Alibaba的分布式微服务权限管理系统,面临业务规则频繁变更与系统耦合度高的挑战。本文将详解如何在RuoYi-Cloud中集成规则引擎,实现业务逻辑与代码解耦,提升系统灵活性与可维护性,解决传统硬编码规则带来的扩展性难题。
剖析规则引擎核心价值
在微服务架构中,业务规则的硬编码会导致系统扩展性差、变更成本高。规则引擎通过将业务规则从代码中剥离,以可配置的形式独立管理,实现"业务规则即数据"的架构理念。对于RuoYi-Cloud这类权限管理系统,规则引擎可显著提升权限策略、审批流程等业务规则的动态调整能力,降低服务间耦合度。
选择适合的规则引擎方案
主流规则引擎技术对比
| 引擎类型 | 技术特性 | 性能表现 | 集成复杂度 | 推荐场景 |
|---|---|---|---|---|
| Drools | 完整规则生命周期管理,支持复杂规则 | 高(优化后) | 中 | 企业级复杂业务规则 |
| EasyRules | 轻量级API,注解驱动 | 中 | 低 | 简单规则场景 |
| QLExpress | 高性能表达式执行,轻量级 | 高 | 中 | 高并发规则计算 |
| MVEL | 动态脚本执行,灵活度高 | 中 | 高 | 动态逻辑执行 |
RuoYi-Cloud适配建议
基于项目微服务架构特性,推荐采用Drools作为核心规则引擎,其优势在于:
- 支持复杂规则网络与推理能力,满足权限管理系统的多层次规则需求
- 完善的规则管理生命周期,支持动态加载与更新
- 与Spring生态良好集成,符合RuoYi-Cloud技术栈
构建基础规则引擎框架
核心思路
通过在公共模块集成Drools,构建规则引擎基础服务,各业务模块通过统一接口调用规则引擎,实现规则执行与业务逻辑分离。
关键实现步骤
1. 添加依赖配置
在ruoyi-common-core模块的pom.xml中添加Drools依赖:
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-core</artifactId>
<version>7.73.0.Final</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-compiler</artifactId>
<version>7.73.0.Final</version>
</dependency>
<dependency>
<groupId>org.kie</groupId>
<artifactId>kie-spring</artifactId>
<version>7.73.0.Final</version>
</dependency>
2. 配置规则引擎
创建DroolsConfig配置类,实现规则文件的加载与Kie容器管理:
@Configuration
public class DroolsConfig {
private static final String RULES_BASE_PATH = "rules/";
@Bean
public KieContainer kieContainer() {
KieServices kieServices = KieServices.Factory.get();
KieFileSystem kieFileSystem = kieServices.newKieFileSystem();
// 加载classpath下所有规则文件
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
try {
Resource[] resources = resolver.getResources("classpath*:" + RULES_BASE_PATH + "**/*.drl");
for (Resource resource : resources) {
String filePath = resource.getURI().toString();
String rulePath = RULES_BASE_PATH + FilenameUtils.getName(filePath);
kieFileSystem.write(ResourceFactory.newClassPathResource(rulePath, "UTF-8"));
}
KieBuilder kieBuilder = kieServices.newKieBuilder(kieFileSystem);
Results results = kieBuilder.verify();
if (results.hasMessages(Message.Level.ERROR)) {
throw new RuntimeException("规则文件编译错误: " + results.getMessages());
}
KieModule kieModule = kieBuilder.getKieModule();
return kieServices.newKieContainer(kieModule.getReleaseId());
} catch (Exception e) {
throw new RuntimeException("初始化规则引擎失败", e);
}
}
}
注意事项
- 规则文件统一放置在
src/main/resources/rules目录下 - 确保规则文件编码格式为UTF-8,避免中文乱码
- 添加编译验证,提前发现规则语法错误
实现动态规则执行服务
核心思路
封装规则引擎服务,提供统一的规则执行接口,支持不同业务场景的规则调用,并实现规则执行结果的标准化处理。
关键代码实现
1. 创建规则服务接口
public interface RuleService {
/**
* 执行规则并返回结果
* @param ruleSessionName 规则会话名称
* @param facts 事实对象列表
* @return 规则执行结果
*/
RuleExecutionResult executeRules(String ruleSessionName, List<Object> facts);
/**
* 执行规则并返回特定类型结果
* @param ruleSessionName 规则会话名称
* @param facts 事实对象列表
* @param resultClass 结果类型
* @return 类型化的规则执行结果
*/
<T> T executeRulesWithResult(String ruleSessionName, List<Object> facts, Class<T> resultClass);
}
2. 实现规则服务
@Service
public class RuleServiceImpl implements RuleService {
private final KieContainer kieContainer;
@Autowired
public RuleServiceImpl(KieContainer kieContainer) {
this.kieContainer = kieContainer;
}
@Override
public RuleExecutionResult executeRules(String ruleSessionName, List<Object> facts) {
RuleExecutionResult result = new RuleExecutionResult();
KieSession kieSession = null;
try {
kieSession = kieContainer.newKieSession(ruleSessionName);
kieSession.setGlobal("ruleResult", result);
// 插入事实对象
if (facts != null && !facts.isEmpty()) {
facts.forEach(kieSession::insert);
}
// 执行规则
int firedRules = kieSession.fireAllRules();
result.setFiredRulesCount(firedRules);
result.setSuccess(true);
} catch (Exception e) {
result.setSuccess(false);
result.setErrorMessage(e.getMessage());
log.error("规则执行异常", e);
} finally {
if (kieSession != null) {
kieSession.dispose();
}
}
return result;
}
// 其他方法实现...
}
注意事项
- 使用KieSession时确保及时释放资源,避免内存泄漏
- 通过全局对象(Global)传递执行结果,便于规则文件中设置结果
- 添加异常处理和日志记录,提高系统可维护性
典型业务场景实践
场景一:动态权限验证
需求描述
实现基于用户角色、部门、数据范围的动态权限验证,支持复杂的权限组合规则。
规则文件实现 (security-permission.drl)
package com.ruoyi.security.rules;
import com.ruoyi.system.domain.SysUser;
import com.ruoyi.system.domain.SysResource;
import com.ruoyi.common.core.domain.RuleExecutionResult;
global RuleExecutionResult ruleResult;
rule "AdminAllPermission"
salience 100
when
$user : SysUser(roleIds contains "1") // 管理员角色ID
$resource : SysResource()
then
ruleResult.addResult("permission", true);
ruleResult.addMessage("管理员拥有全部权限");
drools.halt(); // 终止后续规则执行
end
rule "DeptDataPermission"
when
$user : SysUser(deptId != null)
$resource : SysResource(type == "DATA", dataScope == "DEPT")
then
boolean hasPermission = $user.getDeptId().equals($resource.getDeptId());
ruleResult.addResult("permission", hasPermission);
ruleResult.addMessage(hasPermission ? "拥有部门数据权限" : "无部门数据权限");
end
权限服务调用
@Service
public class PermissionServiceImpl implements IPermissionService {
@Autowired
private RuleService ruleService;
@Override
public boolean hasResourcePermission(SysUser user, SysResource resource) {
List<Object> facts = new ArrayList<>();
facts.add(user);
facts.add(resource);
RuleExecutionResult result = ruleService.executeRules("permissionSession", facts);
return result.getResult("permission", Boolean.class, false);
}
}
场景二:工作流审批规则
需求描述
实现基于金额、申请人职级、部门的多级审批流程自动路由。
规则文件实现 (workflow-approval.drl)
package com.ruoyi.workflow.rules;
import com.ruoyi.workflow.domain.ApprovalRequest;
import com.ruoyi.workflow.domain.ApprovalResult;
global ApprovalResult approvalResult;
rule "ManagerApproval"
when
$request : ApprovalRequest(amount <= 5000,
applicantLevel <= 3)
then
approvalResult.setApproverLevel(4); // 部门经理审批
approvalResult.setApprovalSteps(1);
approvalResult.setMessage("金额≤5000,部门经理审批");
end
rule "DirectorApproval"
when
$request : ApprovalRequest(amount > 5000 && amount <= 20000,
applicantLevel <= 4)
then
approvalResult.setApproverLevel(5); // 总监审批
approvalResult.setApprovalSteps(2);
approvalResult.setMessage("5000<金额≤20000,总监审批");
end
rule "CEOApproval"
when
$request : ApprovalRequest(amount > 20000)
then
approvalResult.setApproverLevel(7); // CEO审批
approvalResult.setApprovalSteps(3);
approvalResult.setMessage("金额>20000,CEO审批");
end
场景三:用户注册验证规则
需求描述
实现用户注册信息的多维度验证,包括邮箱格式、密码强度、手机号验证等。
规则文件实现 (user-validation.drl)
package com.ruoyi.user.rules;
import com.ruoyi.system.domain.SysUser;
import com.ruoyi.common.core.domain.ValidationResult;
global ValidationResult validationResult;
rule "EmailFormatValidation"
when
$user : SysUser(email != null,
email not matches "^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$")
then
validationResult.addError("email", "邮箱格式不正确");
end
rule "PasswordStrengthValidation"
when
$user : SysUser(password != null,
password.length() < 8 ||
!(password matches ".*[A-Z].*") ||
!(password matches ".*[a-z].*") ||
!(password matches ".*[0-9].*"))
then
validationResult.addError("password", "密码必须包含大小写字母和数字,且长度至少8位");
end
优化规则引擎执行性能
规则会话池化管理
@Component
public class KieSessionPoolManager {
private final KieContainer kieContainer;
private final Map<String, BlockingQueue<KieSession>> sessionPools = new ConcurrentHashMap<>();
@Autowired
public KieSessionPoolManager(KieContainer kieContainer) {
this.kieContainer = kieContainer;
// 初始化常用规则会话池
initPool("permissionSession", 10);
initPool("approvalSession", 5);
}
private void initPool(String sessionName, int poolSize) {
BlockingQueue<KieSession> pool = new ArrayBlockingQueue<>(poolSize);
for (int i = 0; i < poolSize; i++) {
pool.offer(createKieSession(sessionName));
}
sessionPools.put(sessionName, pool);
}
private KieSession createKieSession(String sessionName) {
return kieContainer.newKieSession(sessionName);
}
public KieSession borrowSession(String sessionName) {
try {
BlockingQueue<KieSession> pool = sessionPools.get(sessionName);
if (pool == null) {
throw new IllegalArgumentException("未初始化的规则会话池: " + sessionName);
}
return pool.poll(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException("获取规则会话超时", e);
}
}
public void returnSession(String sessionName, KieSession session) {
if (session != null) {
session.reset(); // 重置会话状态
BlockingQueue<KieSession> pool = sessionPools.get(sessionName);
if (pool != null) {
pool.offer(session);
}
}
}
}
规则文件热加载
@Component
public class RuleFileWatcher {
private final KieContainer kieContainer;
private final String rulesPath;
private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
@Autowired
public RuleFileWatcher(KieContainer kieContainer,
@Value("${ruoyi.rule.path:classpath:rules}") String rulesPath) {
this.kieContainer = kieContainer;
this.rulesPath = rulesPath;
startWatcher();
}
private void startWatcher() {
// 每30秒检查一次规则文件变更
scheduler.scheduleAtFixedRate(this::checkRuleChanges, 0, 30, TimeUnit.SECONDS);
}
private void checkRuleChanges() {
// 实现文件变更检测逻辑
// 变更时调用 kieContainer.updateToVersion() 更新规则
}
}
构建规则管理平台
规则管理数据库设计
CREATE TABLE `sys_rule` (
`rule_id` bigint NOT NULL AUTO_INCREMENT COMMENT '规则ID',
`rule_name` varchar(100) NOT NULL COMMENT '规则名称',
`rule_code` varchar(50) NOT NULL COMMENT '规则编码',
`rule_content` longtext COMMENT '规则内容',
`rule_type` varchar(20) NOT NULL COMMENT '规则类型',
`session_name` varchar(50) NOT NULL COMMENT '会话名称',
`status` char(1) NOT NULL DEFAULT '0' COMMENT '状态(0正常 1停用)',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`rule_id`),
UNIQUE KEY `uk_rule_code` (`rule_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='规则定义表';
CREATE TABLE `sys_rule_version` (
`version_id` bigint NOT NULL AUTO_INCREMENT COMMENT '版本ID',
`rule_id` bigint NOT NULL COMMENT '规则ID',
`version_num` int NOT NULL COMMENT '版本号',
`rule_content` longtext COMMENT '规则内容',
`update_by` varchar(64) DEFAULT '' COMMENT '更新者',
`update_time` datetime NOT NULL COMMENT '更新时间',
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`version_id`),
KEY `idx_rule_id` (`rule_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='规则版本表';
规则管理接口实现
@RestController
@RequestMapping("/system/rule")
public class SysRuleController extends BaseController {
@Autowired
private ISysRuleService ruleService;
@GetMapping("/list")
public TableDataInfo list(SysRule sysRule) {
startPage();
List<SysRule> list = ruleService.selectSysRuleList(sysRule);
return getDataTable(list);
}
@GetMapping(value = "/{ruleId}")
public AjaxResult getInfo(@PathVariable("ruleId") Long ruleId) {
return AjaxResult.success(ruleService.selectSysRuleById(ruleId));
}
@PostMapping
public AjaxResult add(@Validated @RequestBody SysRule sysRule) {
if (StringUtils.isNull(sysRule.getRuleId())) {
return toAjax(ruleService.insertSysRule(sysRule));
}
return toAjax(ruleService.updateSysRule(sysRule));
}
@DeleteMapping("/{ruleIds}")
public AjaxResult remove(@PathVariable Long[] ruleIds) {
return toAjax(ruleService.deleteSysRuleByIds(ruleIds));
}
@PostMapping("/deploy/{ruleId}")
public AjaxResult deployRule(@PathVariable Long ruleId) {
ruleService.deployRule(ruleId);
return AjaxResult.success("规则部署成功");
}
}
常见问题排查
规则不执行问题
- 检查规则文件路径:确保规则文件放置在
src/main/resources/rules目录下 - 验证规则语法:使用Drools Workbench或在线DRL验证工具检查语法错误
- 检查KieSession名称:确保代码中使用的session名称与规则文件中定义的一致
- 查看规则条件:确认事实对象是否满足规则的when条件
性能问题优化
- 规则顺序优化:使用salience属性调整规则执行顺序,将高频规则前置
- 减少事实对象:只插入必要的事实对象,避免无关数据进入规则引擎
- 使用规则流:复杂规则场景下使用ruleflow-group控制规则执行流程
- 会话池调优:根据并发量调整会话池大小,避免频繁创建KieSession
规则冲突解决
- 明确规则优先级:使用salience属性设置规则优先级
- 使用activation-group:同一activation-group中的规则只能有一个被执行
- 添加终止条件:在关键规则中使用drools.halt()终止后续规则执行
- 规则拆分:将复杂规则拆分为多个独立规则,降低冲突概率
实战建议与未来扩展
实战建议
- 规则分层管理:按业务领域划分规则文件,如security/、workflow/、validation/等子目录
- 版本控制策略:所有规则变更必须通过版本管理,保留历史版本便于回滚
- 灰度发布:新规则先在测试环境验证,再通过规则管理平台动态部署到生产环境
- 监控告警:实现规则执行监控,对执行异常、执行超时等情况设置告警机制
未来扩展方向
- 规则可视化设计:开发图形化规则编辑器,支持拖拽式规则配置,降低业务人员使用门槛
- AI辅助规则生成:结合NLP技术,实现自然语言描述到规则代码的自动转换
- 规则推荐系统:基于历史规则执行数据,推荐最优规则组合和执行策略
- 分布式规则引擎:实现规则引擎的分布式部署,支持大规模规则并行执行
通过本文介绍的方案,我们在RuoYi-Cloud中构建了功能完善的动态规则引擎,实现了业务规则与代码的解耦,显著提升了系统的灵活性和可维护性。在实际项目中,建议根据业务复杂度合理设计规则粒度,建立完善的规则管理流程,充分发挥规则引擎在微服务架构中的价值。
登录后查看全文
热门项目推荐
相关项目推荐
GLM-5.1GLM-5.1是智谱迄今最智能的旗舰模型,也是目前全球最强的开源模型。GLM-5.1大大提高了代码能力,在完成长程任务方面提升尤为显著。和此前分钟级交互的模型不同,它能够在一次任务中独立、持续工作超过8小时,期间自主规划、执行、自我进化,最终交付完整的工程级成果。Jinja00
MiniMax-M2.7MiniMax-M2.7 是我们首个深度参与自身进化过程的模型。M2.7 具备构建复杂智能体应用框架的能力,能够借助智能体团队、复杂技能以及动态工具搜索,完成高度精细的生产力任务。Python00- QQwen3.5-397B-A17BQwen3.5 实现了重大飞跃,整合了多模态学习、架构效率、强化学习规模以及全球可访问性等方面的突破性进展,旨在为开发者和企业赋予前所未有的能力与效率。Jinja00
HY-Embodied-0.5这是一套专为现实世界具身智能打造的基础模型。该系列模型采用创新的混合Transformer(Mixture-of-Transformers, MoT) 架构,通过潜在令牌实现模态特异性计算,显著提升了细粒度感知能力。Jinja00
LongCat-AudioDiT-1BLongCat-AudioDiT 是一款基于扩散模型的文本转语音(TTS)模型,代表了当前该领域的最高水平(SOTA),它直接在波形潜空间中进行操作。00
ERNIE-ImageERNIE-Image 是由百度 ERNIE-Image 团队开发的开源文本到图像生成模型。它基于单流扩散 Transformer(DiT)构建,并配备了轻量级的提示增强器,可将用户的简短输入扩展为更丰富的结构化描述。凭借仅 80 亿的 DiT 参数,它在开源文本到图像模型中达到了最先进的性能。该模型的设计不仅追求强大的视觉质量,还注重实际生成场景中的可控性,在这些场景中,准确的内容呈现与美观同等重要。特别是,ERNIE-Image 在复杂指令遵循、文本渲染和结构化图像生成方面表现出色,使其非常适合商业海报、漫画、多格布局以及其他需要兼具视觉质量和精确控制的内容创作任务。它还支持广泛的视觉风格,包括写实摄影、设计导向图像以及更多风格化的美学输出。Jinja00
项目优选
收起
OpenHarmony documentation | OpenHarmony开发者文档
Dockerfile
668
4.3 K
deepin linux kernel
C
28
16
Ascend Extension for PyTorch
Python
511
621
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
398
297
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
943
879
🎉 (RuoYi)官方仓库 基于SpringBoot,Spring Security,JWT,Vue3 & Vite、Element Plus 的前后端分离权限管理系统
Vue
1.56 K
905
暂无简介
Dart
917
222
旨在打造算法先进、性能卓越、高效敏捷、安全可靠的密码套件,通过轻量级、可剪裁的软件技术架构满足各行业不同场景的多样化要求,让密码技术应用更简单,同时探索后量子等先进算法创新实践,构建密码前沿技术底座!
C
1.07 K
558
昇腾LLM分布式训练框架
Python
142
169
仓颉编程语言运行时与标准库。
Cangjie
163
924
