在工作流系統中,條件分支往往需要根據運行時上下文動態計算布爾表達式(如 amount > 1000 && user.level == 'VIP')。硬編碼或純 SQL 腳本難以應對複雜邏輯與頻繁變更。Groovy 作為 JVM 友好的動態語言,提供了:
package org.openjweb.core.groovy.test;
import groovy.lang.GroovyClassLoader;
import java.io.File;
public class InvokeGroovy {
public static void main(String[] args) {
ClassLoader parentCL = InvokeGroovy.class.getClassLoader();
GroovyClassLoader groovyCL = new GroovyClassLoader(parentCL);
try {
// 方式一:從文件加載(註釋掉的代碼)
// Class groovyClass = groovyCL.parseClass(new File("D:/.../Foo.groovy"));
// 方式二:直接編譯字符串腳本(推薦用於數據庫存儲場景)
String script = "package org.openjweb.groovy; \n" +
"import org.openjweb.core.groovy.test.IFoo;\n" +
"class Foo implements IFoo {\n" +
" public Object run(Object foo) {\n" +
" return 2 + 2 > 1 // 返回 Boolean\n" +
" }\n" +
"}";
Class<?> groovyClass = groovyCL.parseClass(script);
IFoo foo = (IFoo) groovyClass.newInstance();
System.out.println(foo.run(new Integer(2))); // 輸出:true
} catch (Exception e) {
e.printStackTrace();
}
}
}
// Java 定義接口
package org.openjweb.core.groovy.test;
public interface IFoo {
Object run(Object foo);
}
// Foo.groovy
package org.openjweb.groovy;
import org.openjweb.core.groovy.test.IFoo;
class Foo implements IFoo {
public Object run(Object foo) {
return 3 + 2 // 最後一行表達式值自動返回
}
}
GroovyClassLoader 繼承自 ClassLoader,每次 parseClass 都會生成新的 Class 對象。生產環境建議:
Class(以腳本內容哈希為鍵)通過接口參數傳遞業務上下文:
// Groovy 腳本中訪問 Java 對象屬性
class RuleScript implements IRule {
public boolean evaluate(OrderContext ctx) {
return ctx.totalAmount > 500 && ctx.user.vipLevel == 'GOLD'
}
}
GroovyShell 配合 SecureASTCustomizer 限制危險操作(文件 IO、反射、系統命令)Future.get(timeout) 防止腳本死循環// 數據庫表設計
CREATE TABLE rule_scripts (
id BIGINT PRIMARY KEY,
rule_code VARCHAR(64), // 業務規則編碼
version INT, // 版本號
script_content TEXT, // Groovy 腳本內容
status TINYINT, // 1-啟用 0-禁用
create_time DATETIME
);
運行時根據 rule_code 查詢最新啟用版本,熱加載無需重啟應用。
// 複雜決策邏輯用 Groovy Map/Closure 表達更優雅
def rules = [
{ ctx -> ctx.amount > 10000 ? 'HIGH_RISK' : null },
{ ctx -> ctx.user.age < 18 ? 'MINOR' : null },
{ ctx -> 'NORMAL' } // 默認規則
]
def evaluate(ctx) {
rules.each { rule ->
def result = rule(ctx)
if (result) return result
}
}
| 維度 | Groovy | JRuby | Nashorn (JS) |
|---|---|---|---|
| Java 互操作 | 原生無縫 | 良好 | 需轉換 |
| 語法熟悉度 | Java 開發者極高 | 較低 | 中等 |
| 性能(JIT後) | 優秀 | 良好 | 一般 |
| 生態成熟度 | 高 | 中 | 已棄用(JDK 15移除) |
Groovy 作為 JVM 生態的動態語言首選,憑藉語法親和力、無縫互操作、靈活部署三大優勢,成為 Java 系統實現動態規則引擎的理想選擇。通過 GroovyClassLoader 實現腳本動態編譯、接口契約解耦、沙箱安全防護,可構建出高可用、可熱更新的業務規則中台。隨著業務複雜度提升,此類「代碼即配置、配置即代碼」的架構模式將愈發普及。