基于SpringBoot + QLExpress打造动态规则引擎:让业务规则不再束缚代码!
基于SpringBoot + QLExpress打造动态规则引擎:让业务规则不再束缚代码!
每次业务规则变动都需要修改代码、重新打包、上线部署?客户临时想要调整折扣规则、风控策略或者计费逻辑,你就得加班加点改代码?今天就来聊聊如何基于SpringBoot + QLExpress打造一个强大的动态规则引擎,让业务规则变得灵活可控,再也不用担心频繁变更了!
一、为什么需要动态规则引擎?
在开始技术实现之前,我们先来理解为什么动态规则引擎如此重要。
1.1 传统业务规则的痛点
// 传统业务规则的痛点示例
public class TraditionalBusinessRules {
public void痛点() {
System.out.println("=== 传统业务规则的痛点 ===");
System.out.println("1. 代码硬编码:规则写死在代码里");
System.out.println("2. 变更困难:每次修改都需要重新部署");
System.out.println("3. 发布风险:频繁上线增加系统风险");
System.out.println("4. 响应缓慢:无法快速响应业务需求");
System.out.println("5. 维护成本高:多个版本难以维护");
}
}
1.2 动态规则引擎的价值
// 动态规则引擎的价值
public class DynamicRuleEngineBenefits {
public void benefits() {
System.out.println("=== 动态规则引擎的价值 ===");
System.out.println("1. 业务灵活:规则可动态调整");
System.out.println("2. 快速响应:无需重新部署即可生效");
System.out.println("3. 降低风险:减少代码变更和上线频率");
System.out.println("4. 提升效率:业务人员可自助配置");
System.out.println("5. 统一管理:集中管理所有业务规则");
}
}
二、QLExpress简介与优势
QLExpress是阿里巴巴开源的一款轻量级表达式语言,非常适合用来实现动态规则引擎。
2.1 QLExpress特性
// QLExpress特性
public class QLExpressFeatures {
public void features() {
System.out.println("=== QLExpress特性 ===");
System.out.println("1. 语法简洁:类似Java语法,易于学习");
System.out.println("2. 性能优秀:编译后执行,速度快");
System.out.println("3. 安全可控:沙箱机制,防止恶意代码");
System.out.println("4. 扩展性强:支持自定义函数和宏");
System.out.println("5. 易于集成:与SpringBoot无缝集成");
}
}
2.2 QLExpress与其他规则引擎对比
// QLExpress与其他规则引擎对比
public class RuleEngineComparison {
public void comparison() {
System.out.println("=== 规则引擎对比 ===");
System.out.println("Drools:功能强大但复杂,学习成本高");
System.out.println("QLExpress:轻量级,语法简单,性能好");
System.out.println("Aviator:表达式引擎,功能相对简单");
System.out.println("Groovy:功能强大但性能一般,安全性较差");
System.out.println("推荐:中小型项目选QLExpress,大型复杂项目选Drools");
}
}
三、SpringBoot集成QLExpress
3.1 依赖配置
<!-- pom.xml 添加依赖 -->
<dependencies>
<!-- SpringBoot Web Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- QLExpress -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>QLExpress</artifactId>
<version>3.2.4</version>
</dependency>
<!-- Redis(用于规则缓存) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 数据库(用于规则存储) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- 监控 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
3.2 QLExpress配置类
@Configuration
public class QLExpressConfig {
@Bean
public ExpressRunner expressRunner() {
ExpressRunner runner = new ExpressRunner();
// 注册自定义函数
try {
runner.addFunction("contains", new ContainsFunction());
runner.addFunction("startsWith", new StartsWithFunction());
runner.addFunction("endsWith", new EndsWithFunction());
runner.addFunction("formatDate", new FormatDateFunction());
} catch (Exception e) {
throw new RuntimeException("注册QLExpress函数失败", e);
}
return runner;
}
@Bean
public DefaultContext<String, Object> expressContext() {
return new DefaultContext<>();
}
}
3.3 自定义函数实现
// 自定义函数:字符串包含判断
public class ContainsFunction implements InstructionSetFunction {
@Override
public OperateData callSelf(ExpressionExecutor[] list,
ExpressPackage expressPackage,
RunnerContext context,
ErrorInfo errorInfo) throws Exception {
String source = (String) list[0].getObject(context);
String target = (String) list[1].getObject(context);
boolean result = source != null && source.contains(target);
return new OperateData(result, Boolean.class);
}
}
// 自定义函数:日期格式化
public class FormatDateFunction implements InstructionSetFunction {
@Override
public OperateData callSelf(ExpressionExecutor[] list,
ExpressPackage expressPackage,
RunnerContext context,
ErrorInfo errorInfo) throws Exception {
Date date = (Date) list[0].getObject(context);
String pattern = (String) list[1].getObject(context);
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
String result = sdf.format(date);
return new OperateData(result, String.class);
}
}
四、规则引擎核心实现
4.1 规则实体设计
@Entity
@Table(name = "rule_definitions")
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class RuleDefinition {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "rule_code", nullable = false, unique = true)
private String ruleCode; // 规则编码
@Column(name = "rule_name", nullable = false)
private String ruleName; // 规则名称
@Column(name = "rule_expression", nullable = false, columnDefinition = "text")
private String ruleExpression; // 规则表达式
@Column(name = "rule_description")
private String ruleDescription; // 规则描述
@Column(name = "rule_type", nullable = false)
private String ruleType; // 规则类型(DECISION-决策规则,VALIDATION-校验规则等)
@Column(name = "enabled", nullable = false)
private Boolean enabled = true; // 是否启用
@Column(name = "priority")
private Integer priority = 0; // 优先级
@Column(name = "created_at")
private LocalDateTime createdAt;
@Column(name = "updated_at")
private LocalDateTime updatedAt;
@PrePersist
protected void onCreate() {
createdAt = LocalDateTime.now();
updatedAt = LocalDateTime.now();
}
@PreUpdate
protected void onUpdate() {
updatedAt = LocalDateTime.now();
}
}
4.2 规则存储Repository
@Repository
public interface RuleDefinitionRepository extends JpaRepository<RuleDefinition, Long> {
Optional<RuleDefinition> findByRuleCode(String ruleCode);
List<RuleDefinition> findByEnabledTrueOrderByPriorityDesc();
List<RuleDefinition> findByRuleTypeAndEnabledTrue(String ruleType);
}
4.3 规则引擎服务实现
@Service
@Slf4j
public class RuleEngineService {
@Autowired
private ExpressRunner expressRunner;
@Autowired
private RuleDefinitionRepository ruleRepository;
@Autowired
private RedisTemplate<String, Object> redisTemplate;
private static final String RULE_CACHE_PREFIX = "rule_engine:rule:";
private static final long RULE_CACHE_TTL = 300; // 5分钟缓存
/**
* 执行规则
*/
public RuleExecutionResult executeRule(String ruleCode, Map<String, Object> context) {
try {
// 1. 获取规则定义
RuleDefinition rule = getRuleDefinition(ruleCode);
if (rule == null) {
return RuleExecutionResult.builder()
.success(false)
.errorCode("RULE_NOT_FOUND")
.errorMessage("规则不存在: " + ruleCode)
.build();
}
if (!rule.getEnabled()) {
return RuleExecutionResult.builder()
.success(false)
.errorCode("RULE_DISABLED")
.errorMessage("规则已禁用: " + ruleCode)
.build();
}
// 2. 执行规则表达式
Object result = executeExpression(rule.getRuleExpression(), context);
// 3. 返回执行结果
return RuleExecutionResult.builder()
.success(true)
.result(result)
.ruleCode(ruleCode)
.executedAt(LocalDateTime.now())
.build();
} catch (Exception e) {
log.error("执行规则失败: ruleCode={}", ruleCode, e);
return RuleExecutionResult.builder()
.success(false)
.errorCode("EXECUTION_ERROR")
.errorMessage("规则执行异常: " + e.getMessage())
.build();
}
}
/**
* 批量执行规则
*/
public List<RuleExecutionResult> executeRules(List<String> ruleCodes, Map<String, Object> context) {
return ruleCodes.parallelStream()
.map(ruleCode -> executeRule(ruleCode, context))
.collect(Collectors.toList());
}
/**
* 获取规则定义(带缓存)
*/
private RuleDefinition getRuleDefinition(String ruleCode) {
String cacheKey = RULE_CACHE_PREFIX + ruleCode;
// 先从缓存获取
RuleDefinition cachedRule = (RuleDefinition) redisTemplate.opsForValue().get(cacheKey);
if (cachedRule != null) {
return cachedRule;
}
// 缓存未命中,从数据库获取
Optional<RuleDefinition> ruleOpt = ruleRepository.findByRuleCode(ruleCode);
if (ruleOpt.isPresent()) {
RuleDefinition rule = ruleOpt.get();
// 存入缓存
redisTemplate.opsForValue().set(cacheKey, rule, RULE_CACHE_TTL, TimeUnit.SECONDS);
return rule;
}
return null;
}
/**
* 执行表达式
*/
private Object executeExpression(String expression, Map<String, Object> context) throws Exception {
// 创建执行上下文
DefaultContext<String, Object> expressContext = new DefaultContext<>();
expressContext.putAll(context);
// 执行表达式
Object result = expressRunner.execute(expression, expressContext, null, true, false);
return result;
}
/**
* 验证规则语法
*/
public RuleValidationResult validateRule(String expression) {
try {
expressRunner.checkSyntax(expression);
return RuleValidationResult.builder()
.valid(true)
.message("规则语法正确")
.build();
} catch (Exception e) {
return RuleValidationResult.builder()
.valid(false)
.message("规则语法错误: " + e.getMessage())
.build();
}
}
/**
* 清除规则缓存
*/
public void clearRuleCache(String ruleCode) {
String cacheKey = RULE_CACHE_PREFIX + ruleCode;
redisTemplate.delete(cacheKey);
}
/**
* 清除所有规则缓存
*/
public void clearAllRuleCache() {
Set<String> keys = redisTemplate.keys(RULE_CACHE_PREFIX + "*");
if (keys != null && !keys.isEmpty()) {
redisTemplate.delete(keys);
}
}
}
4.4 规则执行结果封装
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class RuleExecutionResult {
private boolean success;
private String errorCode;
private String errorMessage;
private Object result;
private String ruleCode;
private LocalDateTime executedAt;
private long executionTime; // 执行耗时(毫秒)
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class RuleValidationResult {
private boolean valid;
private String message;
private List<String> errors;
}
五、业务场景实战
5.1 场景一:订单折扣规则
// 订单折扣规则示例
@RestController
@RequestMapping("/api/discount")
@Slf4j
public class DiscountRuleController {
@Autowired
private RuleEngineService ruleEngineService;
/**
* 计算订单折扣
*/
@PostMapping("/calculate")
public ResponseEntity<DiscountResult> calculateDiscount(@RequestBody OrderRequest request) {
try {
// 构造规则执行上下文
Map<String, Object> context = new HashMap<>();
context.put("orderAmount", request.getOrderAmount());
context.put("customerLevel", request.getCustomerLevel());
context.put("productCategory", request.getProductCategory());
context.put("orderTime", new Date());
// 执行折扣规则
RuleExecutionResult result = ruleEngineService.executeRule("DISCOUNT_RULE_001", context);
if (result.isSuccess()) {
Double discountRate = (Double) result.getResult();
BigDecimal discountAmount = request.getOrderAmount().multiply(BigDecimal.valueOf(discountRate));
BigDecimal finalAmount = request.getOrderAmount().subtract(discountAmount);
DiscountResult discountResult = DiscountResult.builder()
.originalAmount(request.getOrderAmount())
.discountRate(discountRate)
.discountAmount(discountAmount)
.finalAmount(finalAmount)
.build();
return ResponseEntity.ok(discountResult);
} else {
return ResponseEntity.badRequest()
.body(DiscountResult.builder()
.errorMessage(result.getErrorMessage())
.build());
}
} catch (Exception e) {
log.error("计算折扣失败", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(DiscountResult.builder()
.errorMessage("系统异常")
.build());
}
}
}
// 示例规则表达式(存储在数据库中)
/*
rule_code: DISCOUNT_RULE_001
rule_name: 订单折扣计算规则
rule_expression:
if (customerLevel == "VIP") {
if (orderAmount > 1000) {
return 0.2; // VIP客户订单金额大于1000元,享受2折
} else {
return 0.1; // VIP客户其他情况,享受1折
}
} else if (customerLevel == "GOLD") {
if (orderAmount > 500) {
return 0.15; // 金牌客户订单金额大于500元,享受1.5折
} else {
return 0.05; // 金牌客户其他情况,享受0.5折
}
} else {
if (orderAmount > 2000) {
return 0.1; // 普通客户订单金额大于2000元,享受1折
} else {
return 0.0; // 普通客户其他情况,无折扣
}
}
*/
5.2 场景二:风控校验规则
// 风控校验规则示例
@Service
@Slf4j
public class RiskControlService {
@Autowired
private RuleEngineService ruleEngineService;
/**
* 风控校验
*/
public RiskCheckResult checkRisk(TransactionRequest request) {
try {
// 构造风控上下文
Map<String, Object> context = new HashMap<>();
context.put("userId", request.getUserId());
context.put("amount", request.getAmount());
context.put("ipAddress", request.getIpAddress());
context.put("deviceType", request.getDeviceType());
context.put("transactionTime", new Date());
context.put("userRiskScore", getUserRiskScore(request.getUserId()));
// 执行风控规则
RuleExecutionResult result = ruleEngineService.executeRule("RISK_CONTROL_RULE_001", context);
if (result.isSuccess()) {
Boolean allowTransaction = (Boolean) result.getResult();
return RiskCheckResult.builder()
.allowed(allowTransaction)
.riskLevel(allowTransaction ? "LOW" : "HIGH")
.checkTime(LocalDateTime.now())
.build();
} else {
// 规则执行失败,默认允许交易但记录日志
log.warn("风控规则执行失败: {}", result.getErrorMessage());
return RiskCheckResult.builder()
.allowed(true)
.riskLevel("UNKNOWN")
.warningMessage("风控检查异常")
.checkTime(LocalDateTime.now())
.build();
}
} catch (Exception e) {
log.error("风控校验异常", e);
// 异常情况下默认允许交易
return RiskCheckResult.builder()
.allowed(true)
.riskLevel("SYSTEM_ERROR")
.errorMessage("系统异常")
.checkTime(LocalDateTime.now())
.build();
}
}
private double getUserRiskScore(Long userId) {
// 获取用户风险评分的逻辑
return 0.5;
}
}
// 示例风控规则表达式
/*
rule_code: RISK_CONTROL_RULE_001
rule_name: 交易风控校验规则
rule_expression:
// 高风险IP地址检查
def highRiskIps = ["192.168.1.100", "10.0.0.1"];
if (highRiskIps.contains(ipAddress)) {
return false; // 高风险IP,拒绝交易
}
// 大额交易检查
if (amount > 10000 && userRiskScore < 0.7) {
return false; // 高额交易且用户风险评分较低,拒绝交易
}
// 异常设备检查
if (deviceType == "emulator" || deviceType == "unknown") {
return false; // 模拟器或未知设备,拒绝交易
}
// 时间段检查
def hour = formatDate(transactionTime, "HH");
if (hour >= "02" && hour <= "05") {
// 凌晨2点到5点,增加额外检查
if (amount > 5000) {
return false; // 凌晨大额交易,拒绝
}
}
return true; // 通过风控检查
*/
六、规则管理后台
6.1 规则管理Controller
@RestController
@RequestMapping("/api/rules")
@Slf4j
public class RuleManagementController {
@Autowired
private RuleEngineService ruleEngineService;
@Autowired
private RuleDefinitionRepository ruleRepository;
/**
* 查询规则列表
*/
@GetMapping
public ResponseEntity<List<RuleDefinition>> listRules(
@RequestParam(required = false) String ruleType,
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "20") int size) {
Pageable pageable = PageRequest.of(page, size, Sort.by("updatedAt").descending());
Page<RuleDefinition> rulePage;
if (StringUtils.hasText(ruleType)) {
rulePage = ruleRepository.findByRuleType(ruleType, pageable);
} else {
rulePage = ruleRepository.findAll(pageable);
}
return ResponseEntity.ok(rulePage.getContent());
}
/**
* 获取规则详情
*/
@GetMapping("/{id}")
public ResponseEntity<RuleDefinition> getRule(@PathVariable Long id) {
Optional<RuleDefinition> rule = ruleRepository.findById(id);
return rule.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
/**
* 创建规则
*/
@PostMapping
public ResponseEntity<RuleDefinition> createRule(@RequestBody RuleDefinition rule) {
// 验证规则语法
RuleValidationResult validationResult = ruleEngineService.validateRule(rule.getRuleExpression());
if (!validationResult.isValid()) {
throw new IllegalArgumentException("规则语法错误: " + validationResult.getMessage());
}
rule.setCreatedAt(LocalDateTime.now());
rule.setUpdatedAt(LocalDateTime.now());
RuleDefinition savedRule = ruleRepository.save(rule);
// 清除相关缓存
ruleEngineService.clearRuleCache(rule.getRuleCode());
return ResponseEntity.ok(savedRule);
}
/**
* 更新规则
*/
@PutMapping("/{id}")
public ResponseEntity<RuleDefinition> updateRule(@PathVariable Long id, @RequestBody RuleDefinition rule) {
Optional<RuleDefinition> existingRule = ruleRepository.findById(id);
if (!existingRule.isPresent()) {
return ResponseEntity.notFound().build();
}
// 验证规则语法
RuleValidationResult validationResult = ruleEngineService.validateRule(rule.getRuleExpression());
if (!validationResult.isValid()) {
throw new IllegalArgumentException("规则语法错误: " + validationResult.getMessage());
}
RuleDefinition updatedRule = existingRule.get();
updatedRule.setRuleName(rule.getRuleName());
updatedRule.setRuleExpression(rule.getRuleExpression());
updatedRule.setRuleDescription(rule.getRuleDescription());
updatedRule.setRuleType(rule.getRuleType());
updatedRule.setEnabled(rule.getEnabled());
updatedRule.setPriority(rule.getPriority());
updatedRule.setUpdatedAt(LocalDateTime.now());
RuleDefinition savedRule = ruleRepository.save(updatedRule);
// 清除相关缓存
ruleEngineService.clearRuleCache(updatedRule.getRuleCode());
return ResponseEntity.ok(savedRule);
}
/**
* 删除规则
*/
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteRule(@PathVariable Long id) {
Optional<RuleDefinition> rule = ruleRepository.findById(id);
if (rule.isPresent()) {
ruleRepository.deleteById(id);
// 清除相关缓存
ruleEngineService.clearRuleCache(rule.get().getRuleCode());
}
return ResponseEntity.ok().build();
}
/**
* 测试规则
*/
@PostMapping("/test")
public ResponseEntity<RuleExecutionResult> testRule(@RequestBody TestRuleRequest request) {
RuleExecutionResult result = ruleEngineService.executeRule(request.getRuleCode(), request.getContext());
return ResponseEntity.ok(result);
}
/**
* 验证规则语法
*/
@PostMapping("/validate")
public ResponseEntity<RuleValidationResult> validateRule(@RequestBody ValidateRuleRequest request) {
RuleValidationResult result = ruleEngineService.validateRule(request.getExpression());
return ResponseEntity.ok(result);
}
/**
* 清除所有规则缓存
*/
@PostMapping("/cache/clear")
public ResponseEntity<String> clearAllCache() {
ruleEngineService.clearAllRuleCache();
return ResponseEntity.ok("缓存清除成功");
}
}
6.2 规则测试请求对象
@Data
@NoArgsConstructor
@AllArgsConstructor
public class TestRuleRequest {
private String ruleCode;
private Map<String, Object> context;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ValidateRuleRequest {
private String expression;
}
七、性能优化与监控
7.1 规则执行监控
@Component
@Slf4j
public class RuleExecutionMetrics {
@Autowired
private MeterRegistry meterRegistry;
private final Counter ruleExecutions;
private final Counter ruleFailures;
private final Timer ruleExecutionTimer;
public RuleExecutionMetrics(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
this.ruleExecutions = Counter.builder("rule.engine.executions")
.description("规则执行次数")
.register(meterRegistry);
this.ruleFailures = Counter.builder("rule.engine.failures")
.description("规则执行失败次数")
.register(meterRegistry);
this.ruleExecutionTimer = Timer.builder("rule.engine.execution.time")
.description("规则执行耗时")
.register(meterRegistry);
}
/**
* 记录规则执行
*/
public void recordRuleExecution(String ruleCode, boolean success, long executionTime) {
ruleExecutions.increment(Tag.of("rule_code", ruleCode), Tag.of("success", String.valueOf(success)));
if (!success) {
ruleFailures.increment(Tag.of("rule_code", ruleCode));
}
ruleExecutionTimer.record(executionTime, TimeUnit.MILLISECONDS);
}
/**
* 获取规则执行统计
*/
public RuleExecutionStats getExecutionStats(String ruleCode) {
// 通过Micrometer获取统计数据
return new RuleExecutionStats();
}
}
7.2 规则缓存优化
@Service
public class OptimizedRuleCacheService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
// 使用本地缓存 + Redis缓存的二级缓存策略
private final Cache<String, RuleDefinition> localCache =
Caffeine.newBuilder()
.maximumSize(1000)
.expireAfterWrite(60, TimeUnit.SECONDS)
.build();
/**
* 获取规则定义(二级缓存)
*/
public RuleDefinition getRuleDefinition(String ruleCode) {
// 1. 先查本地缓存
RuleDefinition rule = localCache.getIfPresent(ruleCode);
if (rule != null) {
return rule;
}
// 2. 查Redis缓存
String cacheKey = "rule_engine:rule:" + ruleCode;
rule = (RuleDefinition) redisTemplate.opsForValue().get(cacheKey);
if (rule != null) {
localCache.put(ruleCode, rule);
return rule;
}
// 3. 查数据库并更新缓存
// 实现逻辑...
return null;
}
}
八、安全与权限控制
8.1 规则编辑权限控制
@RestController
@RequestMapping("/api/rules")
@PreAuthorize("hasRole('ADMIN') or hasRole('RULE_MANAGER')")
public class SecureRuleManagementController {
// 只有管理员或规则管理员才能访问规则管理接口
@PostMapping
@PreAuthorize("hasAuthority('RULE_CREATE')")
public ResponseEntity<RuleDefinition> createRule(@RequestBody RuleDefinition rule) {
// 创建规则需要RULE_CREATE权限
return ResponseEntity.ok(new RuleDefinition());
}
@PutMapping("/{id}")
@PreAuthorize("hasAuthority('RULE_UPDATE')")
public ResponseEntity<RuleDefinition> updateRule(@PathVariable Long id, @RequestBody RuleDefinition rule) {
// 更新规则需要RULE_UPDATE权限
return ResponseEntity.ok(new RuleDefinition());
}
@DeleteMapping("/{id}")
@PreAuthorize("hasAuthority('RULE_DELETE')")
public ResponseEntity<Void> deleteRule(@PathVariable Long id) {
// 删除规则需要RULE_DELETE权限
return ResponseEntity.ok().build();
}
}
8.2 规则表达式安全检查
@Service
public class RuleSecurityValidator {
private static final Set<String> FORBIDDEN_KEYWORDS = Set.of(
"System", "Runtime", "Process", "File", "Thread",
"ClassLoader", "SecurityManager", "exit", "halt"
);
/**
* 检查规则表达式安全性
*/
public boolean isExpressionSafe(String expression) {
// 检查是否包含禁用关键字
for (String keyword : FORBIDDEN_KEYWORDS) {
if (expression.contains(keyword)) {
return false;
}
}
// 检查是否包含危险操作
if (expression.contains("import ") ||
expression.contains("new ") ||
expression.contains("eval(")) {
return false;
}
return true;
}
}
九、最佳实践总结
9.1 规则设计原则
public class RuleDesignPrinciples {
public void principles() {
System.out.println("=== 规则设计原则 ===");
System.out.println("1. 简洁性:规则表达式应尽量简单明了");
System.out.println("2. 可读性:使用有意义的变量名和注释");
System.out.println("3. 可测试性:规则应易于测试和验证");
System.out.println("4. 可维护性:避免过于复杂的嵌套逻辑");
System.out.println("5. 性能考虑:避免在规则中执行耗时操作");
}
}
9.2 运维操作手册
public class OperationsManual {
public void manual() {
System.out.println("=== 规则引擎运维手册 ===");
System.out.println("日常维护:");
System.out.println("- 监控规则执行成功率和响应时间");
System.out.println("- 定期清理过期的规则缓存");
System.out.println("- 备份重要的规则定义");
System.out.println("- 监控Redis缓存使用情况");
System.out.println("\n应急处理:");
System.out.println("- 规则执行异常:检查规则语法和上下文");
System.out.println("- 性能下降:分析慢规则并优化");
System.out.println("- 缓存失效:手动清除缓存并重启服务");
System.out.println("- 数据库连接异常:检查数据库连接池配置");
System.out.println("\n版本升级:");
System.out.println("- 规则语法变更时需要适配");
System.out.println("- 数据库表结构变更时需要迁移");
System.out.println("- 缓存策略变更时需要清理旧缓存");
}
}
结语
通过本文的介绍,相信你已经掌握了如何基于SpringBoot + QLExpress打造一个功能强大的动态规则引擎。这套方案不仅能够满足大多数业务场景的需求,还具有良好的扩展性和维护性。
关键要点总结:
- 选择合适的规则引擎:QLExpress轻量级且易用
- 合理的架构设计:缓存+数据库的存储方案
- 完善的监控体系:性能指标和执行日志
- 安全保障机制:权限控制和表达式安全检查
- 运维友好性:管理后台和操作手册
记住,规则引擎的价值在于让业务变得更加灵活,但也要注意避免过度设计。在实际应用中,要根据业务复杂度和变更频率来决定是否需要引入规则引擎。
如果你觉得这篇文章对你有帮助,欢迎分享给更多的朋友。在规则引擎的探索路上,我们一起成长!
关注「服务端技术精选」,获取更多干货技术文章!
标题:基于SpringBoot + QLExpress打造动态规则引擎:让业务规则不再束缚代码!
作者:jiangyi
地址:http://jiangyi.space/articles/2025/12/21/1766304288922.html
- 一、为什么需要动态规则引擎?
- 1.1 传统业务规则的痛点
- 1.2 动态规则引擎的价值
- 二、QLExpress简介与优势
- 2.1 QLExpress特性
- 2.2 QLExpress与其他规则引擎对比
- 三、SpringBoot集成QLExpress
- 3.1 依赖配置
- 3.2 QLExpress配置类
- 3.3 自定义函数实现
- 四、规则引擎核心实现
- 4.1 规则实体设计
- 4.2 规则存储Repository
- 4.3 规则引擎服务实现
- 4.4 规则执行结果封装
- 五、业务场景实战
- 5.1 场景一:订单折扣规则
- 5.2 场景二:风控校验规则
- 六、规则管理后台
- 6.1 规则管理Controller
- 6.2 规则测试请求对象
- 七、性能优化与监控
- 7.1 规则执行监控
- 7.2 规则缓存优化
- 八、安全与权限控制
- 8.1 规则编辑权限控制
- 8.2 规则表达式安全检查
- 九、最佳实践总结
- 9.1 规则设计原则
- 9.2 运维操作手册
- 结语
0 评论