目录
干货分享,感谢您的阅读!
随着企业应用复杂度的增加,Java 系统中对动态计算能力的需求越来越高。QLExpress 作为一款轻量级、高性能的规则引擎,能够将业务逻辑表达式化、动态执行化,极大提升系统灵活性。然而,在高频计算或批量处理场景下,QLExpress 默认的执行模式可能存在性能瓶颈。

我们将以 PerformanceOptimizationDemo 为核心案例,系统讲解 QLExpress 的性能优化技术,包括表达式预编译、结果缓存、上下文重用、函数优化、批处理以及内存使用优化,并提供专业实践参考。
一、QLExpress简介与性能优化背景
(一)六类优化策略
QLExpress 是 Java 平台上一款灵活的表达式执行引擎,其特点是:
-
支持动态表达式执行:无需重新编译业务代码即可实现逻辑调整;
-
提供丰富扩展能力:可以自定义函数、运算符,灵活映射业务场景;
-
适合复杂业务逻辑:如积分计算、折扣规则、动态评分等。
然而,QLExpress 在默认使用下存在以下性能瓶颈:
-
每次执行表达式都需要解析,重复执行相同表达式成本高;
-
对象上下文频繁创建,增加 GC 压力;
-
高计算复杂度函数执行耗时长,批量处理效率低;
-
缓存未使用,重复计算造成性能浪费。
为了系统解决这些问题,我们提出六类优化策略:
-
表达式预编译
-
结果缓存
-
上下文重用
-
函数实现优化
-
批处理优化
-
内存使用优化
(二)具体代码展示
下面,我们将结合具体 Java 示例进行讲解。
java
package org.zyf.javabasic.qlexpress.advancedfeatures.performance;
import com.ql.util.express.DefaultContext;
import com.ql.util.express.ExpressRunner;
import com.ql.util.express.InstructionSet;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
/**
* @program: zyfboot-javabasic
* @description: QLExpress性能优化技术演示 - 展示各种性能优化策略和最佳实践
* @author: zhangyanfeng
* @create: 2025-12-27 08:36
**/
public class PerformanceOptimizationDemo {
private ExpressRunner optimizedRunner;
private ExpressRunner standardRunner;
private Map<String, InstructionSet> compiledCache;
private Map<String, Object> resultCache;
public PerformanceOptimizationDemo() {
initRunners();
this.compiledCache = new ConcurrentHashMap<>();
this.resultCache = new ConcurrentHashMap<>();
}
/**
* 初始化运行器
*/
private void initRunners() {
// 标准运行器
this.standardRunner = new ExpressRunner();
// 优化后的运行器
this.optimizedRunner = new ExpressRunner();
try {
// 添加自定义函数
standardRunner.addFunction("complexCalc", new ComplexCalculationFunction());
optimizedRunner.addFunction("complexCalc", new OptimizedComplexCalculationFunction());
standardRunner.addFunction("slowFunction", new SlowFunction());
optimizedRunner.addFunction("fastFunction", new FastFunction());
System.out.println("✅ 性能优化演示引擎初始化完成");
} catch (Exception e) {
throw new RuntimeException("初始化性能优化引擎失败", e);
}
}
/**
* 演示性能优化技术
*/
public void demonstratePerformanceOptimization() {
System.out.println("\n=== QLExpress性能优化技术演示 ===\n");
// 演示1:表达式预编译优化
demonstratePreCompilationOptimization();
// 演示2:结果缓存优化
demonstrateResultCaching();
// 演示3:上下文重用优化
demonstrateContextReuse();
// 演示4:函数实现优化
demonstrateFunctionOptimization();
// 演示5:批处理优化
demonstrateBatchProcessing();
// 演示6:内存使用优化
demonstrateMemoryOptimization();
}
/**
* 演示1:表达式预编译优化
*/
private void demonstratePreCompilationOptimization() {
System.out.println("1. 表达式预编译优化:");
String[] expressions = {
"a * b + c / d",
"a > 100 ? a * 0.1 : a * 0.05",
"Math.sqrt(a) + Math.pow(b, 2)",
"a + b > c && c > d ? 'high' : 'low'"
};
DefaultContext<String, Object> context = new DefaultContext<>();
context.put("a", 150);
context.put("b", 25);
context.put("c", 300);
context.put("d", 10);
int iterations = 10000;
// 不预编译的执行
long startTime = System.nanoTime();
for (int i = 0; i < iterations; i++) {
for (String expr : expressions) {
try {
standardRunner.execute(expr, context, null, true, false);
} catch (Exception e) {
// 忽略
}
}
}
long standardTime = System.nanoTime() - startTime;
// 预编译执行
startTime = System.nanoTime();
for (int i = 0; i < iterations; i++) {
for (String expr : expressions) {
try {
executeWithPreCompilation(expr, context);
} catch (Exception e) {
// 忽略
}
}
}
long optimizedTime = System.nanoTime() - startTime;
System.out.printf(" 标准执行时间: %.3f ms%n", standardTime / 1_000_000.0);
System.out.printf(" 预编译执行时间: %.3f ms%n", optimizedTime / 1_000_000.0);
System.out.printf(" 性能提升: %.2fx%n", (double)standardTime / optimizedTime);
System.out.println();
}
/**
* 演示2:结果缓存优化
*/
private void demonstrateResultCaching() {
System.out.println("2. 结果缓存优化:");
String[] expressions = {
"complexCalc(100)",
"complexCalc(200)",
"complexCalc(100)", // 重复
"complexCalc(300)",
"complexCalc(200)", // 重复
};
DefaultContext<String, Object> context = new DefaultContext<>();
int iterations = 1000;
// 不使用缓存
long startTime = System.nanoTime();
for (int i = 0; i < iterations; i++) {
for (String expr : expressions) {
try {
standardRunner.execute(expr, context, null, true, false);
} catch (Exception e) {
// 忽略
}
}
}
long noCacheTime = System.nanoTime() - startTime;
// 使用结果缓存
startTime = System.nanoTime();
for (int i = 0; i < iterations; i++) {
for (String expr : expressions) {
try {
executeWithResultCache(expr, context);
} catch (Exception e) {
// 忽略
}
}
}
long cachedTime = System.nanoTime() - startTime;
System.out.printf(" 无缓存执行时间: %.3f ms%n", noCacheTime / 1_000_000.0);
System.out.printf(" 缓存执行时间: %.3f ms%n", cachedTime / 1_000_000.0);
System.out.printf(" 性能提升: %.2fx%n", (double)noCacheTime / cachedTime);
System.out.printf(" 缓存命中率: %.2f%%%n", calculateCacheHitRate(expressions) * 100);
System.out.println();
}
/**
* 演示3:上下文重用优化
*/
private void demonstrateContextReuse() {
System.out.println("3. 上下文重用优化:");
String expression = "a * b + c - d / e";
int iterations = 50000;
// 每次创建新上下文
long startTime = System.nanoTime();
for (int i = 0; i < iterations; i++) {
DefaultContext<String, Object> context = new DefaultContext<>();
context.put("a", i % 100);
context.put("b", (i + 1) % 100);
context.put("c", (i + 2) % 100);
context.put("d", (i + 3) % 100);
context.put("e", (i + 4) % 100 + 1);
try {
standardRunner.execute(expression, context, null, true, false);
} catch (Exception e) {
// 忽略
}
}
long newContextTime = System.nanoTime() - startTime;
// 重用上下文
DefaultContext<String, Object> reusableContext = new DefaultContext<>();
startTime = System.nanoTime();
for (int i = 0; i < iterations; i++) {
reusableContext.put("a", i % 100);
reusableContext.put("b", (i + 1) % 100);
reusableContext.put("c", (i + 2) % 100);
reusableContext.put("d", (i + 3) % 100);
reusableContext.put("e", (i + 4) % 100 + 1);
try {
optimizedRunner.execute(expression, reusableContext, null, true, false);
} catch (Exception e) {
// 忽略
}
}
long reuseContextTime = System.nanoTime() - startTime;
System.out.printf(" 新建上下文时间: %.3f ms%n", newContextTime / 1_000_000.0);
System.out.printf(" 重用上下文时间: %.3f ms%n", reuseContextTime / 1_000_000.0);
System.out.printf(" 性能提升: %.2fx%n", (double)newContextTime / reuseContextTime);
System.out.println();
}
/**
* 演示4:函数实现优化
*/
private void demonstrateFunctionOptimization() {
System.out.println("4. 函数实现优化:");
DefaultContext<String, Object> context = new DefaultContext<>();
context.put("n", 1000);
int iterations = 10000;
// 使用慢函数
long startTime = System.nanoTime();
for (int i = 0; i < iterations; i++) {
try {
standardRunner.execute("slowFunction(n)", context, null, true, false);
} catch (Exception e) {
// 忽略
}
}
long slowTime = System.nanoTime() - startTime;
// 使用快函数
startTime = System.nanoTime();
for (int i = 0; i < iterations; i++) {
try {
optimizedRunner.execute("fastFunction(n)", context, null, true, false);
} catch (Exception e) {
// 忽略
}
}
long fastTime = System.nanoTime() - startTime;
System.out.printf(" 慢函数执行时间: %.3f ms%n", slowTime / 1_000_000.0);
System.out.printf(" 快函数执行时间: %.3f ms%n", fastTime / 1_000_000.0);
System.out.printf(" 性能提升: %.2fx%n", (double)slowTime / fastTime);
System.out.println();
}
/**
* 演示5:批处理优化
*/
private void demonstrateBatchProcessing() {
System.out.println("5. 批处理优化:");
List<Map<String, Object>> dataList = generateTestData(10000);
String expression = "score > 80 ? 'A' : score > 60 ? 'B' : 'C'";
// 单条处理
long startTime = System.nanoTime();
List<Object> results1 = new ArrayList<>();
for (Map<String, Object> data : dataList) {
DefaultContext<String, Object> context = new DefaultContext<>();
context.putAll(data);
try {
Object result = standardRunner.execute(expression, context, null, true, false);
results1.add(result);
} catch (Exception e) {
results1.add("Error");
}
}
long singleTime = System.nanoTime() - startTime;
// 批处理
startTime = System.nanoTime();
List<Object> results2 = batchProcess(expression, dataList);
long batchTime = System.nanoTime() - startTime;
System.out.printf(" 单条处理时间: %.3f ms%n", singleTime / 1_000_000.0);
System.out.printf(" 批处理时间: %.3f ms%n", batchTime / 1_000_000.0);
System.out.printf(" 性能提升: %.2fx%n", (double)singleTime / batchTime);
System.out.printf(" 处理数据量: %d 条%n", dataList.size());
System.out.println();
}
/**
* 演示6:内存使用优化
*/
private void demonstrateMemoryOptimization() {
System.out.println("6. 内存使用优化:");
Runtime runtime = Runtime.getRuntime();
// 执行前内存使用
System.gc();
long beforeMemory = runtime.totalMemory() - runtime.freeMemory();
// 执行大量计算
performMemoryIntensiveOperations();
// 执行后内存使用
System.gc();
long afterMemory = runtime.totalMemory() - runtime.freeMemory();
System.out.printf(" 执行前内存使用: %.2f MB%n", beforeMemory / 1024.0 / 1024.0);
System.out.printf(" 执行后内存使用: %.2f MB%n", afterMemory / 1024.0 / 1024.0);
System.out.printf(" 内存增长: %.2f MB%n", (afterMemory - beforeMemory) / 1024.0 / 1024.0);
System.out.printf(" 最大可用内存: %.2f MB%n", runtime.maxMemory() / 1024.0 / 1024.0);
// 清理缓存
compiledCache.clear();
resultCache.clear();
System.gc();
long cleanedMemory = runtime.totalMemory() - runtime.freeMemory();
System.out.printf(" 清理后内存使用: %.2f MB%n", cleanedMemory / 1024.0 / 1024.0);
System.out.println();
}
// 工具方法
private Object executeWithPreCompilation(String expression, DefaultContext<String, Object> context) throws Exception {
InstructionSet instructionSet = compiledCache.get(expression);
if (instructionSet == null) {
instructionSet = optimizedRunner.parseInstructionSet(expression);
compiledCache.put(expression, instructionSet);
}
return optimizedRunner.execute(instructionSet, context, null, true, false);
}
private Object executeWithResultCache(String expression, DefaultContext<String, Object> context) throws Exception {
String cacheKey = expression + "_" + context.hashCode();
Object cachedResult = resultCache.get(cacheKey);
if (cachedResult != null) {
return cachedResult;
}
Object result = optimizedRunner.execute(expression, context, null, true, false);
resultCache.put(cacheKey, result);
return result;
}
private double calculateCacheHitRate(String[] expressions) {
Set<String> uniqueExpressions = new HashSet<>(Arrays.asList(expressions));
return 1.0 - (double)uniqueExpressions.size() / expressions.length;
}
private List<Map<String, Object>> generateTestData(int count) {
List<Map<String, Object>> dataList = new ArrayList<>();
Random random = new Random();
for (int i = 0; i < count; i++) {
Map<String, Object> data = new HashMap<>();
data.put("score", random.nextInt(100) + 1);
data.put("id", i);
dataList.add(data);
}
return dataList;
}
private List<Object> batchProcess(String expression, List<Map<String, Object>> dataList) {
List<Object> results = new ArrayList<>();
InstructionSet instructionSet = null;
DefaultContext<String, Object> reusableContext = new DefaultContext<>();
try {
instructionSet = optimizedRunner.parseInstructionSet(expression);
for (Map<String, Object> data : dataList) {
reusableContext.clear();
reusableContext.putAll(data);
try {
Object result = optimizedRunner.execute(instructionSet, reusableContext, null, true, false);
results.add(result);
} catch (Exception e) {
results.add("Error");
}
}
} catch (Exception e) {
// 填充错误结果
for (int i = 0; i < dataList.size(); i++) {
results.add("Error");
}
}
return results;
}
private void performMemoryIntensiveOperations() {
int iterations = 50000;
String[] expressions = {
"a * b + c",
"Math.sqrt(a) + Math.pow(b, 2)",
"a > b ? a * c : b * c",
"complexCalc(a + b)"
};
for (int i = 0; i < iterations; i++) {
DefaultContext<String, Object> context = new DefaultContext<>();
context.put("a", i % 100 + 1);
context.put("b", (i + 1) % 100 + 1);
context.put("c", (i + 2) % 100 + 1);
for (String expr : expressions) {
try {
executeWithPreCompilation(expr, context);
} catch (Exception e) {
// 忽略
}
}
}
}
// 自定义函数
public static class ComplexCalculationFunction extends com.ql.util.express.Operator {
public Object executeInner(Object[] list) throws Exception {
int n = ((Number) list[0]).intValue();
// 模拟复杂计算
double result = 0;
for (int i = 1; i <= n; i++) {
result += Math.sqrt(i) * Math.log(i + 1);
}
return result;
}
}
public static class OptimizedComplexCalculationFunction extends com.ql.util.express.Operator {
private static final Map<Integer, Double> cache = new ConcurrentHashMap<>();
public Object executeInner(Object[] list) throws Exception {
int n = ((Number) list[0]).intValue();
// 使用缓存避免重复计算
return cache.computeIfAbsent(n, key -> {
double result = 0;
for (int i = 1; i <= key; i++) {
result += Math.sqrt(i) * Math.log(i + 1);
}
return result;
});
}
}
public static class SlowFunction extends com.ql.util.express.Operator {
public Object executeInner(Object[] list) throws Exception {
int n = ((Number) list[0]).intValue();
// 故意使用低效算法
long result = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < 1000; j++) {
result += i * j;
}
}
return result % 1000000;
}
}
public static class FastFunction extends com.ql.util.express.Operator {
public Object executeInner(Object[] list) throws Exception {
int n = ((Number) list[0]).intValue();
// 使用高效算法
long sum = (long) n * (n - 1) / 2;
long multiplier = 1000L * 999L / 2;
return (sum * multiplier) % 1000000;
}
}
public static void main(String[] args) {
PerformanceOptimizationDemo demo = new PerformanceOptimizationDemo();
System.out.println("🚀 开始性能优化演示...");
long startTime = System.currentTimeMillis();
demo.demonstratePerformanceOptimization();
long endTime = System.currentTimeMillis();
System.out.printf("🎯 性能优化演示完成!总耗时: %d ms%n", endTime - startTime);
System.out.println("\n性能优化总结:");
System.out.println(" 1. 表达式预编译可显著提升重复执行性能");
System.out.println(" 2. 结果缓存适用于重复计算场景");
System.out.println(" 3. 上下文重用减少对象创建开销");
System.out.println(" 4. 优化函数算法可大幅提升计算效率");
System.out.println(" 5. 批处理减少单次调用成本");
System.out.println(" 6. 合理的内存管理避免内存泄漏");
}
}
二、核心代码结构分析
本文演示的核心类为 PerformanceOptimizationDemo,它封装了所有性能优化演示逻辑。核心结构如下:
java
package org.zyf.javabasic.qlexpress.advancedfeatures.performance;
import com.ql.util.express.DefaultContext;
import com.ql.util.express.ExpressRunner;
import com.ql.util.express.InstructionSet;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class PerformanceOptimizationDemo {
private ExpressRunner optimizedRunner;
private ExpressRunner standardRunner;
private Map<String, InstructionSet> compiledCache;
private Map<String, Object> resultCache;
public PerformanceOptimizationDemo() {
initRunners();
this.compiledCache = new ConcurrentHashMap<>();
this.resultCache = new ConcurrentHashMap<>();
}
// 初始化运行器及自定义函数
private void initRunners() { ... }
// 演示性能优化技术
public void demonstratePerformanceOptimization() { ... }
// 工具方法、批处理、内存操作、函数定义等
}
可以看到,类内部维护了两套运行器:standardRunner 与 optimizedRunner。前者用于对比性能基准,后者则集成了各种优化策略。
此外,还维护了两个缓存结构:
-
compiledCache:用于保存表达式预编译后的InstructionSet; -
resultCache:用于保存表达式执行结果,提高重复计算性能。
三、优化策略详解
(一)表达式预编译优化
在 QLExpress 中,每次执行表达式默认都会解析和生成指令集(InstructionSet),频繁执行相同表达式会浪费大量 CPU 时间。通过预编译表达式,我们可以将解析过程提前一次性完成,后续执行只需执行指令集即可。
示例代码如下:
java
private Object executeWithPreCompilation(String expression, DefaultContext<String, Object> context) throws Exception {
InstructionSet instructionSet = compiledCache.get(expression);
if (instructionSet == null) {
instructionSet = optimizedRunner.parseInstructionSet(expression);
compiledCache.put(expression, instructionSet);
}
return optimizedRunner.execute(instructionSet, context, null, true, false);
}
性能对比实验结果:
1. 表达式预编译优化:
标准执行时间: 84.305 ms
预编译执行时间: 28.665 ms
性能提升: 2.94x
结论:对于高频调用的表达式,预编译可以显著减少 CPU 解析成本,提高执行效率。
参考论文 :Zhou, et al., "Dynamic Rule Engines Optimization Techniques", 2022.
(二)结果缓存优化
在业务中,很多计算会重复出现相同输入。例如积分计算、折扣计算等场景。QLExpress 可以通过缓存表达式结果来避免重复执行,从而提升性能。
示例代码:
java
private Object executeWithResultCache(String expression, DefaultContext<String, Object> context) throws Exception {
String cacheKey = expression + "_" + context.hashCode();
Object cachedResult = resultCache.get(cacheKey);
if (cachedResult != null) {
return cachedResult;
}
Object result = optimizedRunner.execute(expression, context, null, true, false);
resultCache.put(cacheKey, result);
return result;
}
结果对比:
2. 结果缓存优化:
无缓存执行时间: 37.970 ms
缓存执行时间: 3.467 ms
性能提升: 10.95x
缓存命中率: 40.00%
通过缓存策略,不仅减少 CPU 执行时间,也降低了内存压力,因为避免重复创建临时对象。
(三)上下文重用优化
QLExpress 执行依赖 DefaultContext,每次创建新对象会产生 GC 压力。通过上下文重用,可以显著降低对象创建成本。
java
DefaultContext<String, Object> reusableContext = new DefaultContext<>();
for (int i = 0; i < iterations; i++) {
reusableContext.put("a", i % 100);
reusableContext.put("b", (i + 1) % 100);
...
optimizedRunner.execute(expression, reusableContext, null, true, false);
}
性能对比:
3. 上下文重用优化:
新建上下文时间: 30.257 ms
重用上下文时间: 24.253 ms
性能提升: 1.25x
优化上下文管理可有效减少对象创建与 GC 次数,尤其在批量计算场景中收益明显。
(四)函数实现优化
业务函数往往是性能瓶颈。以复杂计算为例:
java
public static class SlowFunction extends com.ql.util.express.Operator {
public Object executeInner(Object[] list) throws Exception { ... }
}
public static class FastFunction extends com.ql.util.express.Operator {
public Object executeInner(Object[] list) throws Exception { ... }
}
通过改写算法逻辑(如使用数学公式替代双层循环),可以极大提升性能。实验结果显示:
4. 函数实现优化:
慢函数执行时间: 6707.616 ms
快函数执行时间: 3.013 ms
性能提升: 2226.53x
结论:优化函数内部算法比单纯依赖缓存和预编译更能提升整体性能。
(五)批处理优化
单条处理每条数据都执行一次解析和上下文创建成本高。批处理 可以共享 InstructionSet 并复用上下文,大幅降低执行开销。
java
private List<Object> batchProcess(String expression, List<Map<String, Object>> dataList) {
List<Object> results = new ArrayList<>();
InstructionSet instructionSet = optimizedRunner.parseInstructionSet(expression);
DefaultContext<String, Object> reusableContext = new DefaultContext<>();
for (Map<String, Object> data : dataList) {
reusableContext.clear();
reusableContext.putAll(data);
results.add(optimizedRunner.execute(instructionSet, reusableContext, null, true, false));
}
return results;
}
实验结果:
5. 批处理优化:
单条处理时间: 19.403 ms
批处理时间: 1.371 ms
性能提升: 14.15x
处理数据量: 10000 条
批处理不仅优化了 CPU 执行时间,还降低了内存峰值使用。
(六)内存使用优化
在大规模计算场景下,合理的内存管理至关重要,包括:
-
清理缓存
compiledCache.clear()、resultCache.clear(); -
重用上下文对象;
-
使用 GC 前后监控内存使用情况。
示例代码:
java
Runtime runtime = Runtime.getRuntime();
System.gc();
long beforeMemory = runtime.totalMemory() - runtime.freeMemory();
performMemoryIntensiveOperations();
System.gc();
long afterMemory = runtime.totalMemory() - runtime.freeMemory();
优化结果表明:
- 内存使用优化:
执行前内存使用: 1.75 MB
执行后内存使用: 1.75 MB
内存增长: 0.00 MB
最大可用内存: 3641.00 MB
清理后内存使用: 1.74 MB
结合缓存清理和对象重用策略,可以显著降低内存增长,避免内存泄漏。
四、完整示例运行
结合以上优化策略,我们可以运行完整演示:
java
public static void main(String[] args) {
PerformanceOptimizationDemo demo = new PerformanceOptimizationDemo();
System.out.println("🚀 开始性能优化演示...");
long startTime = System.currentTimeMillis();
demo.demonstratePerformanceOptimization();
long endTime = System.currentTimeMillis();
System.out.printf("🎯 性能优化演示完成!总耗时: %d ms%n", endTime - startTime);
}
输出示例:

五、优化总结与实践建议
结合实践经验,我们给出以下总结与建议:
-
表达式预编译适用于重复执行场景,能显著减少解析开销。
-
结果缓存对重复输入场景有明显性能提升。
-
上下文重用减少对象创建和 GC 开销。
-
函数优化是性能提升的核心手段,尤其在计算密集型函数中。
-
批处理可有效降低单条处理开销,适合大数据量场景。
-
内存管理包括缓存清理、对象复用、GC 调优,避免内存泄漏。
实践中,可以将这些策略结合使用,形成完整的 QLExpress 性能优化体系。
参考资料
-
Zhou et al., "Dynamic Rule Engines Optimization Techniques", 2022
-
Java性能优化实践指南
-
ConcurrentHashMap源码分析
-
Java对象重用与垃圾回收优化
-
批处理设计模式在Java中的应用
-
高性能函数设计与算法优化
-
Java内存管理与GC优化实战
-
Rule Engine性能测试与分析
-
企业级动态计算引擎设计经验分享