精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

告別硬編碼:阿里開源的動態(tài)腳本引擎 QLExpress ,真香!

開發(fā) 開發(fā)工具
本文全面介紹了 ??QLExpress?? 作為阿里巴巴開源的一款輕量級動態(tài)腳本引擎的主要功能和應(yīng)用場景,并深入講解了其在規(guī)則引擎和業(yè)務(wù)場景中的使用優(yōu)勢。

現(xiàn)代業(yè)務(wù)系統(tǒng)中,如何實現(xiàn)快速、靈活的規(guī)則配置和動態(tài)決策,成為了企業(yè)提升響應(yīng)速度和智能化水平的關(guān)鍵。阿里巴巴開源的 QLExpress 引擎,以其輕量、高效、簡潔的優(yōu)勢,為復(fù)雜業(yè)務(wù)邏輯的動態(tài)處理提供了一種創(chuàng)新的解決方案。

無論是需要實時調(diào)整規(guī)則的電商促銷,還是依賴規(guī)則動態(tài)性的金融風(fēng)控,QLExpress 都能以其靈活的表達(dá)式和易用的規(guī)則配置,實現(xiàn)高效而精準(zhǔn)的業(yè)務(wù)決策。

如果你正在尋找一款強(qiáng)大、靈活的動態(tài)腳本引擎,那么 QLExpress 可能正是你需要的工具!

一、QLExpress快速了解

QLExpress(Quick Language Express)是阿里巴巴開源的一門動態(tài)腳本引擎解析工具,起源于阿里巴巴的電商業(yè)務(wù),旨在解決業(yè)務(wù)規(guī)則、表達(dá)式、數(shù)學(xué)計算等動態(tài)腳本的解析問題。其具有以下基本特點:

  • 線程安全: QLExpress被設(shè)計為線程安全的動態(tài)腳本引擎,它使用threadlocal類型的臨時變量,確保在引擎運(yùn)算過程中的并發(fā)場景下的線程安全性。
  • 高效執(zhí)行: 為了提高執(zhí)行效率,QLExpress在編譯過程中可以將比較耗時的腳本編譯結(jié)果緩存到本地機(jī)器。此外,運(yùn)行時的臨時變量創(chuàng)建采用了緩沖池技術(shù),以確保高效的運(yùn)行時性能,使其與一些性能優(yōu)秀的腳本引擎(如Groovy)相當(dāng)。
  • 弱類型腳本語言: QLExpress采用弱類型腳本語言,語法類似于Groovy和JavaScript。這使得業(yè)務(wù)規(guī)則的表達(dá)更加靈活,雖然相對于強(qiáng)類型腳本語言可能略慢,但在業(yè)務(wù)的靈活性方面提供了很大的優(yōu)勢。
  • 安全控制: QLExpress提供了一些運(yùn)行時參數(shù)的設(shè)置,以進(jìn)行安全控制。通過這些參數(shù),可以預(yù)防一些潛在的安全問題,如死循環(huán)或?qū)Ω呶O到y(tǒng)API的調(diào)用。
  • 代碼精簡、依賴最小: QLExpress的設(shè)計追求代碼的精簡和最小依賴,其jar包大小為250k,適用于所有Java的運(yùn)行環(huán)境。這使得它在各種環(huán)境中都能輕松部署和運(yùn)行,包括在Android系統(tǒng)的低端POS機(jī)上廣泛應(yīng)用。

總體而言,這些特性使QLExpress成為一個在阿里電商業(yè)務(wù)場景中得到廣泛應(yīng)用的強(qiáng)大工具,具有高效、靈活和安全的特點。

二、QLExpress與常用規(guī)則引擎對比

圖片圖片

Drools適用于復(fù)雜的業(yè)務(wù)規(guī)則,而Aviator和QLExpress適用于相對簡單的表達(dá)式計算和規(guī)則。EasyRule更適合簡單規(guī)則場景,特別是面向非專業(yè)開發(fā)人員的情況。最終選擇取決于具體需求,包括業(yè)務(wù)規(guī)則的復(fù)雜性、性能要求、開發(fā)人員技能水平以及項目的特定場景。

三、快速引用和一般工作原理簡訴

1.引用與基本演示

在 Maven 項目中引入 QLExpress,需要在項目的 pom.xml 文件中添加相關(guān)的依賴:

<dependencies>
    <dependency>
        <groupId>com.ql</groupId>
        <artifactId>qlExpress</artifactId>
        <version>3.2.2</version> <!-- 使用實際版本號 -->
    </dependency>
</dependencies>

以下展示簡單演示如何使用 QLExpress 計算折扣后的金額。在實際項目中,可能需要更復(fù)雜的腳本和上下文,以適應(yīng)業(yè)務(wù)需求。

package org.zyf.javabasic.qlexpress;

import com.ql.util.express.DefaultContext;
import com.ql.util.express.ExpressRunner;

/**
 * @program: zyfboot-javabasic
 * @description: 演示如何使用 QLExpress 計算折扣后的金額
 * @author: zhangyanfeng
 **/
publicclass QLExpressExample {
    public static void main(String[] args) {
        try {
            // 創(chuàng)建 QLExpress 引擎
            ExpressRunner runner = new ExpressRunner();

            // 創(chuàng)建上下文并設(shè)置變量
            DefaultContext<String, Object> context = new DefaultContext<>();
            context.put("amount", 1000);
            context.put("discount", 0.1);

            // 執(zhí)行腳本
            String expression = "amount * (1 - discount)";
            Object result = runner.execute(expression, context, null, true, false);

            // 輸出結(jié)果
            System.out.println("Result: " + result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

2.一般工作原理說明

QLExpress的一般工作原理,包括語法樹分析、上下文和執(zhí)行過程。

圖片圖片

  • 語法樹分析: QLExpress會先將輸入的腳本進(jìn)行詞法分析和語法分析,生成一棵語法樹。這個語法樹表示了腳本的結(jié)構(gòu),將其組織成可以被執(zhí)行的形式。
  • 上下文: 在QLExpress中,上下文是一個關(guān)鍵概念。它是腳本執(zhí)行時的環(huán)境,包含變量、函數(shù)等信息。在執(zhí)行腳本之前,你可以向上下文中添加變量,定義函數(shù),設(shè)置一些執(zhí)行參數(shù)等。這樣,腳本執(zhí)行時可以引用上下文中的內(nèi)容。
  • 執(zhí)行過程: QLExpress的執(zhí)行過程包括編譯和運(yùn)行兩個主要階段。在編譯階段,腳本被解析并生成可以執(zhí)行的指令序列。在運(yùn)行階段,這些指令被執(zhí)行,從而實現(xiàn)腳本的功能。

在這個框架下,二次定制的功能擴(kuò)展可以包括:

  • 自定義操作符和函數(shù): 可以通過實現(xiàn)自定義的操作符和函數(shù),使得腳本能夠執(zhí)行特定的業(yè)務(wù)邏輯。
  • 修改執(zhí)行流程: 可以在執(zhí)行階段插入自定義的邏輯,改變腳本執(zhí)行的流程。
  • 定制編譯過程: 在編譯階段定制特定的優(yōu)化或變換,以滿足特殊需求。
  • 擴(kuò)展上下文功能: 可以添加一些上下文的攔截器,使得在腳本執(zhí)行前后可以執(zhí)行額外的邏輯。

這樣的擴(kuò)展點允許更好地適應(yīng)特定的業(yè)務(wù)場景和需求。

四、基本語法學(xué)習(xí)

1.操作符

QLExpress 支持一系列操作符,包括算術(shù)運(yùn)算符、比較運(yùn)算符、邏輯運(yùn)算符等。

圖片圖片

定義一個 Calculator 類,其中包含一些數(shù)字和一個用戶對象,然后使用 QLExpress 進(jìn)行一些簡單的運(yùn)算和條件判斷。

package org.zyf.javabasic.qlexpress;

import com.ql.util.express.DefaultContext;
import com.ql.util.express.ExpressRunner;

/**
 * @program: zyfboot-javabasic
 * @description: 一些簡單的運(yùn)算和條件判斷
 * @author: zhangyanfeng
 **/
publicclass Calculator {
    public static void main(String[] args) {
        try {
            ExpressRunner runner = new ExpressRunner();
            DefaultContext<String, Object> context = new DefaultContext<>();

            // 設(shè)置變量
            context.put("a", 10);
            context.put("b", 5);

            // 算術(shù)運(yùn)算示例
            executeAndPrint(runner, context, "a + b", "Addition");

            // 比較運(yùn)算示例
            executeAndPrint(runner, context, "a > b", "Greater than");

            // 邏輯運(yùn)算示例
            executeAndPrint(runner, context, "a > 0 && b > 0", "Logical AND");

            // 三元運(yùn)算示例
            executeAndPrint(runner, context, "a > b ? 'a is greater' : 'b is greater'", "Ternary Operator");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void executeAndPrint(ExpressRunner runner, DefaultContext<String, Object> context, String expression, String operation) throws Exception {
        // 執(zhí)行腳本
        Object result = runner.execute(expression, context, null, true, false);

        // 輸出結(jié)果
        System.out.println(operation + ": " + result);
    }
}

2.Java對象操作

基本的 Java 語法和對象操作在 QLExpress 中同樣適用,演示在 QLExpress 中使用 Java 語法和進(jìn)行對象操作:

package org.zyf.javabasic.qlexpress;

import com.ql.util.express.DefaultContext;
import com.ql.util.express.ExpressRunner;

/**
 * @program: zyfboot-javabasic
 * @description: 基本的 Java 語法和對象操作
 * @author: zhangyanfeng
 **/
publicclass QLExpressJavaSyntaxExample {
    public static void main(String[] args) {
        try {
            ExpressRunner runner = new ExpressRunner();
            DefaultContext<String, Object> context = new DefaultContext<>();

            // 創(chuàng)建一個用戶對象
            User user = new User("John", 25);
            context.put("user", user);

            // 使用 Java 語法訪問對象屬性和調(diào)用方法
            executeAndPrint(runner, context, "user.getName()", "Accessing Object Property");
            executeAndPrint(runner, context, "user.getAge() + 5", "Performing Arithmetic with Object Property");

            // 使用 Java 語法進(jìn)行對象操作
            executeAndPrint(runner, context, "user.age = 30", "Modifying Object Property");

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void executeAndPrint(ExpressRunner runner, DefaultContext<String, Object> context, String expression, String operation) throws Exception {
        // 執(zhí)行腳本
        Object result = runner.execute(expression, context, null, true, false);

        // 輸出結(jié)果
        System.out.println(operation + ": " + result);
    }

    // 用戶對象類
    staticclass User {
        private String name;
        privateint age;

        public User(String name, int age) {
            this.name = name;
            this.age = age;
        }

        public String getName() {
            return name;
        }

        public int getAge() {
            return age;
        }
    }
}

3.腳本中定義function

在QLExpress中,可以通過 function 關(guān)鍵字來定義函數(shù)。以下是一個簡單的示例:

package org.zyf.javabasic.qlexpress;

import com.ql.util.express.DefaultContext;
import com.ql.util.express.ExpressRunner;

/**
 * @program: zyfboot-javabasic
 * @description: 通過 function 關(guān)鍵字來定義函數(shù)
 * @author: zhangyanfeng
 **/
publicclass QLExpressFunctionExample {
    public static void main(String[] args) {
        try {
            final String express = "function add(int a, int b){\n" +
                    "  return a + b;\n" +
                    "};\n" +
                    "\n" +
                    "function sub(int a, int b){\n" +
                    "  return a - b;\n" +
                    "};\n" +
                    "\n" +
                    "a = 10;\n" +
                    "result = add(a, 4) + sub(a, 9);\n" +
                    "return result;";
            ExpressRunner runner = new ExpressRunner();
            DefaultContext<String, Object> context = new DefaultContext<>();

            // 執(zhí)行腳本
            Object result = runner.execute(express, context, null, true, false);

            // 輸出腳本執(zhí)行結(jié)果
            System.out.println("Result: " + result);

            // 輸出函數(shù)調(diào)用過程中的參數(shù)和返回值
            System.out.println("add function call: a + 4 = " + context.get("a") + " + 4 = " + context.get("result"));

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

4.擴(kuò)展操作符

在 QLExpress 中,可以通過自定義操作符(Operator)來擴(kuò)展語言的功能。

package org.zyf.javabasic.qlexpress;

import com.ql.util.express.DefaultContext;
import com.ql.util.express.ExpressRunner;

import java.util.ArrayList;
import java.util.List;

/**
 * @program: zyfboot-javabasic
 * @description: 自定義操作符(Operator)來擴(kuò)展語言的功能
 * @author: zhangyanfeng
 **/
publicclass QLExpressOperatorExample {
    public static void main(String[] args) {
        try {
            // 示例 1:替換 if then else 關(guān)鍵字
            ExpressRunner runner1 = new ExpressRunner();
            DefaultContext<String, Object> context1 = new DefaultContext<>();
            context1.put("語文",120);
            context1.put("數(shù)學(xué)",23);
            context1.put("英語",23);

            runner1.addOperatorWithAlias("如果", "if", null);
            runner1.addOperatorWithAlias("則", "then", null);
            runner1.addOperatorWithAlias("否則", "else", null);

            String express1 = "如果 (語文 + 數(shù)學(xué) + 英語 > 270) 則 {return 1;} 否則 {return 0;}";
            Object result1 = runner1.execute(express1, context1, null, false, false, 100L);
            System.out.println("Result 1: " + result1); // 輸出結(jié)果 1

            // 示例 2:自定義 Operator
            ExpressRunner runner2 = new ExpressRunner();
            DefaultContext<String, Object> context2 = new DefaultContext<>();

            // 自定義 Operator
            runner2.addOperator("join", new JoinOperator());

            // 示例 2.1:addOperator
            Object result2_1 = runner2.execute("1 join 2 join 3", context2, null, false, false);
            System.out.println("Result 2.1: " + result2_1); // 輸出結(jié)果 [1, 2, 3]

            // 示例 2.2:replaceOperator
            ExpressRunner runner2_2 = new ExpressRunner();
            runner2_2.replaceOperator("+", new JoinOperator());
            Object result2_2 = runner2_2.execute("1 + 2 + 3", context2, null, false, false);
            System.out.println("Result 2.2: " + result2_2); // 輸出結(jié)果 [1, 2, 3]

            // 示例 2.3:addFunction
            ExpressRunner runner2_3 = new ExpressRunner();
            runner2_3.addFunction("join", new JoinOperator());
            Object result2_3 = runner2_3.execute("join(1, 2, 3)", context2, null, false, false);
            System.out.println("Result 2.3: " + result2_3); // 輸出結(jié)果 [1, 2, 3]

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // JoinOperator 類的定義
    publicstaticclass JoinOperator extends com.ql.util.express.Operator {
        public Object executeInner(Object[] list) throws Exception {
            Object opdata1 = list[0];
            Object opdata2 = list[1];
            if (opdata1 instanceof List) {
                ((List) opdata1).add(opdata2);
                return opdata1;
            } else {
                List result = new ArrayList();
                for (Object opdata : list) {
                    result.add(opdata);
                }
                return result;
            }
        }
    }
}

5.綁定Java類或?qū)ο蟮膍ethon

在 QLExpress 中,可使用 addFunctionOfClassMethod 和 addFunctionOfServiceMethod 方法來綁定 Java 類或?qū)ο蟮姆椒ā?/p>

package org.zyf.javabasic.qlexpress;

import com.ql.util.express.DefaultContext;
import com.ql.util.express.ExpressRunner;

/**
 * @program: zyfboot-javabasic
 * @description: 可以使用 addFunctionOfClassMethod 和 addFunctionOfServiceMethod 方法來綁定 Java 類或?qū)ο蟮姆椒? * @author: zhangyanfeng
 * @create: 2023-11-19 16:13
 **/
publicclass QLExpressFunctionBindingExample {
    public static void main(String[] args) {
        try {
            ExpressRunner runner = new ExpressRunner();
            DefaultContext<String, Object> context = new DefaultContext<>();

            // 綁定 Math 類的 abs 方法
            runner.addFunctionOfClassMethod("取絕對值", Math.class.getName(), "abs", new String[]{"double"}, null);

            // 綁定 BeanExample 類的 upper 方法
            runner.addFunctionOfClassMethod("轉(zhuǎn)換為大寫", BeanExample.class.getName(), "upper", new String[]{"String"}, null);

            // 綁定 System.out 的 println 方法
            runner.addFunctionOfServiceMethod("打印", System.out, "println", new String[]{"String"}, null);

            // 綁定 BeanExample 對象的 anyContains 方法
            runner.addFunctionOfServiceMethod("contains", new BeanExample(), "anyContains", new Class[]{String.class, String.class}, null);

            String express = "取絕對值(-100); 轉(zhuǎn)換為大寫(\"hello world\"); 打印(\"你好嗎?\"); contains(\"helloworld\", \"aeiou\")";
            Object result = runner.execute(express, context, null, false, false);

            System.out.println("Result: " + result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    publicstaticclass BeanExample {
        public static double abs(double value) {
            System.out.println("取絕對值結(jié)果: " + value);
            return Math.abs(value);
        }

        public static String upper(String abc) {
            System.out.println("轉(zhuǎn)換為大寫結(jié)果: " + abc.toUpperCase());
            return abc.toUpperCase();
        }

        public boolean anyContains(String str, String searchStr) {
            char[] s = str.toCharArray();
            for (char c : s) {
                if (searchStr.contains(c + "")) {
                    returntrue;
                }
            }
            returnfalse;
        }
    }
}

6.宏定義(macro)

在QLExpress中,宏定義(macro)允許將一個表達(dá)式片段命名為宏,并在其他地方引用這個宏。當(dāng)需要在多個地方使用相同的復(fù)雜表達(dá)式時非常有用,可以提高代碼的可讀性和維護(hù)性。

package org.zyf.javabasic.qlexpress;

import com.ql.util.express.DefaultContext;
import com.ql.util.express.ExpressRunner;

/**
 * @program: zyfboot-javabasic
 * @description: macro 宏定義
 * @author: zhangyanfeng
 **/
publicclass QLExpressMacroExample {
    public static void main(String[] args) {
        try {
            ExpressRunner runner = new ExpressRunner();
            DefaultContext<String, Object> context = new DefaultContext<>();

            // 定義宏
            runner.addMacro("計算平均成績", "(語文+數(shù)學(xué)+英語)/3.0");
            runner.addMacro("是否優(yōu)秀", "計算平均成績>90");

            // 設(shè)置變量值
            context.put("語文", 88);
            context.put("數(shù)學(xué)", 99);
            context.put("英語", 95);

            // 執(zhí)行表達(dá)式并打印結(jié)果
            Object result = runner.execute("是否優(yōu)秀", context, null, false, false);
            System.out.println("Result: " + result);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

7.編譯腳本查詢外部需要定義的變量和函數(shù)

在QLExpress中,編譯腳本并查詢外部需要定義的變量和函數(shù)可以通過 ExpressRunner 提供的一些方法來實現(xiàn)。

package org.zyf.javabasic.qlexpress;

import com.ql.util.express.DefaultContext;
import com.ql.util.express.ExpressRunner;

/**
 * @program: zyfboot-javabasic
 * @description: 編譯腳本,查詢外部需要定義的變量和函數(shù)。
 * @author: zhangyanfeng
 **/
publicclass QLExpressCompileExample {
    public static void main(String[] args) {
        try {
            ExpressRunner runner = new ExpressRunner(true, true);
            DefaultContext<String, Object> context = new DefaultContext<>();
            context.put("語文",120);
            context.put("數(shù)學(xué)",23);
            context.put("英語",23);
            context.put("綜合考試",235);

            // 定義腳本
            String express = "double 平均分 = (語文 + 數(shù)學(xué) + 英語 + 綜合考試) / 4.0; return 平均分";

            // 查詢外部需要定義的變量
            String[] variableNames = runner.getOutVarNames(express);
            System.out.println("外部需要定義的變量:");
            for (String variableName : variableNames) {
                System.out.println("var : " + variableName);
            }

            // 查詢外部需要定義的函數(shù)
            String[] functionNames = runner.getOutFunctionNames(express);
            System.out.println("\n外部需要定義的函數(shù):");
            for (String functionName : functionNames) {
                System.out.println("function : " + functionName);
            }

            // 編譯腳本并執(zhí)行
            Object result = runner.execute(express, context, null, false, false);
            System.out.println("\n腳本執(zhí)行結(jié)果: " + result);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

看下對應(yīng)打印結(jié)果:

執(zhí)行的表達(dá)式:double 平均分 = (語文 + 數(shù)學(xué) + 英語 + 綜合考試) / 4.0; return 平均分
單詞分解結(jié)果:{double},{平均分},{=},{(},{語文},{+},{數(shù)學(xué)},{+},{英語},{+},{綜合考試},{)},{/},{4.0},{;},{return},{平均分}
預(yù)處理后結(jié)果:{double},{平均分},{=},{(},{語文},{+},{數(shù)學(xué)},{+},{英語},{+},{綜合考試},{)},{/},{4.0},{;},{return},{平均分}
單詞分析結(jié)果:double:CONST_CLASS,平均分:ID,=:=,(:(,語文:ID,+:+,數(shù)學(xué):ID,+:+,英語:ID,+:+,綜合考試:ID,):),/:/,4.0:CONST_DOUBLE,;:;,return:return,平均分:ID
最后的語法樹:
1:   STAT_BLOCK:STAT_BLOCK                                                          STAT_BLOCK
2:      STAT_SEMICOLON:STAT_SEMICOLON STAT_SEMICOLON
3:         =:= =
4:            def:def def
5:               double:CONST_CLASS CONST_CLASS
5:               平均分:CONST_STRING CONST
4:            /:/ /
5:               (:CHILD_EXPRESS CHILD_EXPRESS
6:                  +:+ +
7:                     +:+ +
8:                        +:+ +
9:                           語文:ID ID
9:                           數(shù)學(xué):ID ID
8:                        英語:ID ID
7:                     綜合考試:ID ID
5:               4.0:CONST_DOUBLE CONST
2:      STAT_SEMICOLON:STAT_SEMICOLON STAT_SEMICOLON
3:         return:returnreturn
4:            平均分:ID ID


1:LoadData Class:double
2:LoadData 平均分
3:OP : def OPNUMBER[2]
4:LoadAttr:語文
5:LoadAttr:數(shù)學(xué)
6:OP : + OPNUMBER[2]
7:LoadAttr:英語
8:OP : + OPNUMBER[2]
9:LoadAttr:綜合考試
10:OP : + OPNUMBER[2]
11:LoadData 4.0
12:OP : / OPNUMBER[2]
13:OP : = OPNUMBER[2]
14:clearDataStack
15:LoadAttr:平均分
16:return [value]

外部需要定義的變量:
var : 數(shù)學(xué)
var : 綜合考試
var : 英語
var : 語文
執(zhí)行的表達(dá)式:double 平均分 = (語文 + 數(shù)學(xué) + 英語 + 綜合考試) / 4.0; return 平均分
單詞分解結(jié)果:{double},{平均分},{=},{(},{語文},{+},{數(shù)學(xué)},{+},{英語},{+},{綜合考試},{)},{/},{4.0},{;},{return},{平均分}
預(yù)處理后結(jié)果:{double},{平均分},{=},{(},{語文},{+},{數(shù)學(xué)},{+},{英語},{+},{綜合考試},{)},{/},{4.0},{;},{return},{平均分}
單詞分析結(jié)果:double:CONST_CLASS,平均分:ID,=:=,(:(,語文:ID,+:+,數(shù)學(xué):ID,+:+,英語:ID,+:+,綜合考試:ID,):),/:/,4.0:CONST_DOUBLE,;:;,return:return,平均分:ID
最后的語法樹:
1:   STAT_BLOCK:STAT_BLOCK                                                          STAT_BLOCK
2:      STAT_SEMICOLON:STAT_SEMICOLON STAT_SEMICOLON
3:         =:= =
4:            def:def def
5:               double:CONST_CLASS CONST_CLASS
5:               平均分:CONST_STRING CONST
4:            /:/ /
5:               (:CHILD_EXPRESS CHILD_EXPRESS
6:                  +:+ +
7:                     +:+ +
8:                        +:+ +
9:                           語文:ID ID
9:                           數(shù)學(xué):ID ID
8:                        英語:ID ID
7:                     綜合考試:ID ID
5:               4.0:CONST_DOUBLE CONST
2:      STAT_SEMICOLON:STAT_SEMICOLON STAT_SEMICOLON
3:         return:returnreturn
4:            平均分:ID ID


1:LoadData Class:double
2:LoadData 平均分
3:OP : def OPNUMBER[2]
4:LoadAttr:語文
5:LoadAttr:數(shù)學(xué)
6:OP : + OPNUMBER[2]
7:LoadAttr:英語
8:OP : + OPNUMBER[2]
9:LoadAttr:綜合考試
10:OP : + OPNUMBER[2]
11:LoadData 4.0
12:OP : / OPNUMBER[2]
13:OP : = OPNUMBER[2]
14:clearDataStack
15:LoadAttr:平均分
16:return [value]


外部需要定義的函數(shù):
執(zhí)行的表達(dá)式:double 平均分 = (語文 + 數(shù)學(xué) + 英語 + 綜合考試) / 4.0; return 平均分
單詞分解結(jié)果:{double},{平均分},{=},{(},{語文},{+},{數(shù)學(xué)},{+},{英語},{+},{綜合考試},{)},{/},{4.0},{;},{return},{平均分}
預(yù)處理后結(jié)果:{double},{平均分},{=},{(},{語文},{+},{數(shù)學(xué)},{+},{英語},{+},{綜合考試},{)},{/},{4.0},{;},{return},{平均分}
單詞分析結(jié)果:double:CONST_CLASS,平均分:ID,=:=,(:(,語文:ID,+:+,數(shù)學(xué):ID,+:+,英語:ID,+:+,綜合考試:ID,):),/:/,4.0:CONST_DOUBLE,;:;,return:return,平均分:ID
最后的語法樹:
1:   STAT_BLOCK:STAT_BLOCK                                                          STAT_BLOCK
2:      STAT_SEMICOLON:STAT_SEMICOLON STAT_SEMICOLON
3:         =:= =
4:            def:def def
5:               double:CONST_CLASS CONST_CLASS
5:               平均分:CONST_STRING CONST
4:            /:/ /
5:               (:CHILD_EXPRESS CHILD_EXPRESS
6:                  +:+ +
7:                     +:+ +
8:                        +:+ +
9:                           語文:ID ID
9:                           數(shù)學(xué):ID ID
8:                        英語:ID ID
7:                     綜合考試:ID ID
5:               4.0:CONST_DOUBLE CONST
2:      STAT_SEMICOLON:STAT_SEMICOLON STAT_SEMICOLON
3:         return:returnreturn
4:            平均分:ID ID


1:LoadData Class:double
2:LoadData 平均分
3:OP : def OPNUMBER[2]
4:LoadAttr:語文
5:LoadAttr:數(shù)學(xué)
6:OP : + OPNUMBER[2]
7:LoadAttr:英語
8:OP : + OPNUMBER[2]
9:LoadAttr:綜合考試
10:OP : + OPNUMBER[2]
11:LoadData 4.0
12:OP : / OPNUMBER[2]
13:OP : = OPNUMBER[2]
14:clearDataStack
15:LoadAttr:平均分
16:return [value]


腳本執(zhí)行結(jié)果: 100.25

8.不定參數(shù)的使用

在QLExpress中,可以通過使用不定參數(shù)(動態(tài)參數(shù))來處理方法的參數(shù)。

package org.zyf.javabasic.qlexpress;

import com.ql.util.express.DefaultContext;
import com.ql.util.express.DynamicParamsUtil;
import com.ql.util.express.ExpressRunner;

/**
 * @program: zyfboot-javabasic
 * @description: 不定參數(shù)的使用
 * @author: zhangyanfeng
 **/
publicclass QLExpressDynamicParamsExample {
    public static void main(String[] args) {
        try {
            // 創(chuàng)建 ExpressRunner 實例
            ExpressRunner runner = new ExpressRunner();

            // 創(chuàng)建 DefaultContext 實例
            DefaultContext<String, Object> expressContext = new DefaultContext<>();

            // 在 runner 中添加一個函數(shù),使用不定參數(shù)
            runner.addFunctionOfServiceMethod("getTemplate", new QLExpressDynamicParamsExample(), "getTemplate",
                    new Class[]{Object[].class}, null);

            // 調(diào)用 getTemplate 方法,傳遞數(shù)組作為參數(shù)
            Object resultWithArray = runner.execute("getTemplate([11, '22', 33L, true])",
                    expressContext, null, false, false);
            System.out.println("Result with Array: " + resultWithArray);

            // 打開全局開關(guān),啟用動態(tài)參數(shù)調(diào)用
            DynamicParamsUtil.supportDynamicParams = true;

            // 調(diào)用 getTemplate 方法,傳遞多個參數(shù)
            Object resultWithDynamicParams = runner.execute("getTemplate(11, '22', 33L, true)", expressContext,
                    null, false, false);
            System.out.println("Result with Dynamic Params: " + resultWithDynamicParams);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 等價于 getTemplate(Object[] params)
    public Object getTemplate(Object... params) {
        StringBuilder result = new StringBuilder();
        for (Object obj : params) {
            result.append(obj).append(",");
        }
        return result.toString();
    }
}

9.集合的快捷用法

在QLExpress中,你可以使用一些快捷的語法來操作集合。

package org.zyf.javabasic.qlexpress;

import com.ql.util.express.DefaultContext;
import com.ql.util.express.ExpressRunner;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @program: zyfboot-javabasic
 * @description: 集合操作
 * @author: zhangyanfeng
 **/
publicclass QLExpressCollectionOperationsExample {
    public static void main(String[] args) {
        try {
            ExpressRunner runner = new ExpressRunner();
            DefaultContext<String, Object> context = new DefaultContext<>();

            // 使用NewMap創(chuàng)建Map
            String expressMap = "abc = NewMap(1:1, 2:2); return abc.get(1) + abc.get(2);";
            Object resultMap = runner.execute(expressMap, context, null, false, false);
            System.out.println("NewMap Result: " + resultMap);

            // 使用NewList創(chuàng)建List
            String expressList = "abc = NewList(1, 2, 3); return abc.get(1) + abc.get(2);";
            Object resultList = runner.execute(expressList, context, null, false, false);
            System.out.println("NewList Result: " + resultList);

            // 使用方括號[]創(chuàng)建List
            String expressSquareBrackets = "abc = [1, 2, 3]; return abc[1] + abc[2];";
            Object resultSquareBrackets = runner.execute(expressSquareBrackets, context, null, false, false);
            System.out.println("Square Brackets Result: " + resultSquareBrackets);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

10.集合的遍歷

類似java的語法,只是ql不支持for(obj:list){}的語法,只能通過下標(biāo)訪問。

package org.zyf.javabasic.qlexpress;

import com.ql.util.express.DefaultContext;
import com.ql.util.express.ExpressRunner;

import java.util.HashMap;
import java.util.Map;

/**
 * @program: zyfboot-javabasic
 * @description: 使用foreach關(guān)鍵字結(jié)合索引遍歷集合
 * @author: zhangyanfeng
 **/
publicclass QLExpressCollectionTraversalExample {
    public static void main(String[] args) {
        try {
            ExpressRunner runner = new ExpressRunner();
            DefaultContext<String, Object> context = new DefaultContext<>();

            // 創(chuàng)建一個Map
            Map<String, String> map = new HashMap<>();
            map.put("a", "a_value");
            map.put("b", "b_value");

            // 將Map放入上下文中
            context.put("map", map);

            // 遍歷Map
            String express = "keySet = map.keySet();\n" +
                    "objArr = keySet.toArray();\n" +
                    "for (i = 0; i < objArr.length; i++) {\n" +
                    "    key = objArr[i];\n" +
                    "    System.out.println(map.get(key));\n" +
                    "}";
            runner.execute(express, context, null, false, false);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

四、總結(jié)

本文全面介紹了 QLExpress 作為阿里巴巴開源的一款輕量級動態(tài)腳本引擎的主要功能和應(yīng)用場景,并深入講解了其在規(guī)則引擎和業(yè)務(wù)場景中的使用優(yōu)勢。通過對比其他規(guī)則引擎的性能與靈活性,QLExpress 展現(xiàn)了其在處理動態(tài)規(guī)則、復(fù)雜計算邏輯、實時決策等方面的獨(dú)特優(yōu)勢,尤其適用于需要動態(tài)配置業(yè)務(wù)規(guī)則的場景。在實際應(yīng)用中,QLExpress 的簡潔語法、快速上手和高性能表現(xiàn),使其成為了企業(yè)動態(tài)業(yè)務(wù)處理的有效工具。

未來,QLExpress 還可以進(jìn)一步優(yōu)化和拓展,以支持更多場景和定制化功能。對于希望在系統(tǒng)中靈活應(yīng)用規(guī)則邏輯、提升業(yè)務(wù)決策效率的開發(fā)者來說,QLExpress 是一個值得關(guān)注和嘗試的工具。

希望通過本文的介紹,大家能更好地理解和應(yīng)用 QLExpress,從而在項目中實現(xiàn)更高效、更靈活的規(guī)則管理。

責(zé)任編輯:武曉燕 來源: 碼猿技術(shù)專欄
相關(guān)推薦

2025-09-08 02:00:00

2025-02-04 11:30:10

2023-10-31 12:42:00

Spring動態(tài)增刪啟停

2025-07-17 10:30:11

2025-08-01 09:38:00

2025-11-10 03:10:00

2025-02-07 08:16:26

Java開發(fā)者代碼

2022-03-23 15:19:00

低代碼開源阿里巴巴

2025-06-23 00:00:05

2023-08-09 08:01:38

場景Redis接口

2015-09-28 14:27:12

硬編默認(rèn)選擇

2019-05-07 14:42:03

深度學(xué)習(xí)編程人工智能

2022-12-19 08:32:57

項目Feign框架

2025-06-03 08:20:00

Feign微服務(wù)

2021-01-18 06:43:54

程序員公務(wù)員996

2018-12-17 09:57:11

服務(wù)器LinuxBoot開源

2022-03-21 08:30:13

開源模型訓(xùn)練預(yù)測引擎

2021-06-11 10:53:40

Folly組件開發(fā)

2020-12-30 09:33:37

開源茅臺神器

2024-12-26 00:14:45

C#腳本開源
點贊
收藏

51CTO技術(shù)棧公眾號

国产私拍精品| 国产这里有精品| 成人在线黄色| 欧美国产禁国产网站cc| 成人精品在线观看| 久久免费黄色网址| 香蕉视频一区| 欧美人伦禁忌dvd放荡欲情| 99re99热| 无码精品在线观看| 香蕉久久夜色精品国产| 色悠悠久久88| 国产成人精品一区二区在线小狼| 欧美另类老肥妇| 国产精品久久久久国产精品日日| av激情久久| 国产一级片av| 国产一区亚洲| 在线精品91av| 精品人妻一区二区三区日产| 7788色淫网站小说| 国产美女网站视频| 一区二区三区四区精品视频| 色先锋aa成人| 69精品丰满人妻无码视频a片| 日本黄在线观看| 国产一区二区日韩精品| 欧美又大又粗又长| 18岁成人毛片| 欧美在线免费看视频| 精品精品国产高清a毛片牛牛| 不卡av免费在线| 不卡av免费观看| 国产精品福利一区二区三区| 久久综合九九| 性生活视频软件| 另类欧美日韩国产在线| 国产91成人video| 九九热国产精品视频| 日韩成人免费| 亚洲天堂第一页| 中文字幕在线播放一区| 韩国一区二区三区视频| 欧美综合视频在线观看| 丰满爆乳一区二区三区| wwwwxxxx在线观看| 1000精品久久久久久久久| 欧美一进一出视频| 视频午夜在线| 白白色 亚洲乱淫| 3d蒂法精品啪啪一区二区免费| 亚洲视频久久久| 日本91福利区| 国产精品免费久久久久久| 精品国产午夜福利| 在线一区视频| 性欧美激情精品| 国产精品自拍视频一区| 伊人激情综合| 欧美大片欧美激情性色a∨久久| 亚洲女人久久久| 色天天久久综合婷婷女18| 在线视频日韩精品| 精品成人无码一区二区三区| 妖精视频一区二区三区免费观看| 日韩不卡中文字幕| 成年人网站免费看| 欧美日韩破处| 亚洲美女喷白浆| 四虎国产精品成人免费入口| 久久99免费视频| 国产午夜精品全部视频在线播放| 一区二区伦理片| 欧美艳星介绍134位艳星| 国产亚洲一区二区在线| 精品日韩在线视频| 国产精品麻豆久久| 欧美猛男性生活免费| 免费在线观看av网址| 激情久久久久| 日本亚洲欧美成人| 亚洲天堂视频在线| 国产毛片精品视频| 国产精品视频免费一区| 欧美一区二区视频| 国产精品婷婷午夜在线观看| 在线丝袜欧美日韩制服| 四虎影视国产在线视频| 婷婷成人综合网| 日韩av一二三四| 色婷婷成人网| 亚洲国产精品成人va在线观看| 播金莲一级淫片aaaaaaa| 成人在线免费观看网站| 欧美日本精品在线| 国产高清中文字幕| 黄一区二区三区| 国内精品久久国产| 在线免费观看黄色网址| 亚洲一区二区影院| 人妻无码视频一区二区三区| 亚洲男人在线| 亚洲国产精品999| 青青青手机在线视频| 在线精品一区二区| 91精品美女在线| 天堂在线视频免费观看| 国产精品你懂的在线| 成人小视频在线观看免费| 免费亚洲电影| 欧美变态tickling挠脚心| 韩国无码一区二区三区精品| 欧美xxav| 欧美综合第一页| 精品黑人一区二区三区国语馆| 91色在线porny| 日本高清xxxx| 婷婷六月国产精品久久不卡| 91精品国产综合久久精品麻豆| 在线观看国产免费视频| 久久久久国产精品| 国产成人激情视频| 丰满岳乱妇国产精品一区| 日本一区二区三区四区 | 九九九九九伊人| 日韩激情网站| 久久777国产线看观看精品| 69视频免费看| 99国产精品久久久久久久久久| 一区二区三区四区免费观看| 日本精品不卡| 亚洲精品国产精品久久清纯直播 | 色丁香婷婷综合久久| 亚洲欧美综合色| 嫩草影院国产精品| 免费欧美视频| 性色av一区二区三区免费| av中文字幕在线免费观看| 国产精品久久看| 国产免费视频传媒| 日韩系列在线| 91国产精品91| 亚洲老妇色熟女老太| 亚洲色图视频免费播放| 可以看污的网站| 成人女性视频| 国产精品久久中文| 国产精品四虎| 在线观看一区日韩| av男人的天堂av| 日韩在线播放一区二区| 蜜桃成人免费视频| 中文字幕资源网在线观看免费| 亚洲国产欧美日韩精品| 日韩乱码在线观看| 成+人+亚洲+综合天堂| 国产一区 在线播放| 91精品国产自产在线丝袜啪| 久久电影一区二区| 午夜精品久久久久久久99老熟妇| 亚洲免费观看高清| 久久发布国产伦子伦精品| 在线观看日韩| 97人人模人人爽视频一区二区| 超碰个人在线| 日韩一区二区三区电影| 久久久久久久九九九九| 丁香激情综合五月| 精品无码国模私拍视频| 色吊丝一区二区| 日本国产一区二区三区| 国产特黄在线| 91精品麻豆日日躁夜夜躁| 黄色在线观看免费| 成人一级片网址| 成人一对一视频| 九九综合九九| 国产日产欧美精品| 亚洲精品白浆| 日韩精品视频免费| 91青青草视频| 《视频一区视频二区| 18禁一区二区三区| 亚洲欧美视频| 中文字幕一区二区三区有限公司 | 欧美日韩xx| 欧美性猛交xxxx乱大交| 阿v天堂2014| 国产一区二区福利视频| 国产夫妻自拍一区| 同性恋视频一区| 国产精品一区二区久久久久| 国产福利视频在线| 亚洲黄色免费三级| 中文天堂在线播放| 亚洲美女在线一区| 日本免费福利视频| 麻豆高清免费国产一区| 中文字幕日韩精品无码内射| 日本午夜精品| 国产中文欧美精品| 91福利区在线观看| 伊人精品在线观看| 成人午夜免费在线观看| 色av综合在线| 青娱乐91视频| 国产欧美日韩精品一区| wwwww在线观看| 强制捆绑调教一区二区| 福利在线一区二区| 欧美少妇xxxx| 国产免费一区二区| 91精品亚洲一区在线观看| 97高清免费视频| 免费人成在线观看播放视频| 亚洲精品mp4| 99热在线只有精品| 欧美在线观看一区二区| 午夜偷拍福利视频| **性色生活片久久毛片| 免费毛片视频网站| fc2成人免费人成在线观看播放| 97超碰成人在线| 久久精品成人| 黄色片网址在线观看| 一区二区在线| 五月天综合网| 国产成人一二| 91亚洲国产成人久久精品网站| 久久天堂av| 2019最新中文字幕| 波多野在线观看| 欧美精品在线网站| 亚洲乱亚洲乱妇| 亚洲深夜福利网站| 天天av综合网| 精品少妇一区二区| 国产成人精品一区二区无码呦| 精品视频1区2区3区| 无码人妻丰满熟妇区五十路| 亚洲午夜三级在线| 激情综合网五月天| 亚洲综合免费观看高清完整版 | 日日碰狠狠丁香久燥| 亚洲二区免费| 91国在线高清视频| 在线中文一区| 欧美性受xxxx黑人猛交88| 91精品国产黑色瑜伽裤| 久操成人av| 免费观看30秒视频久久| 日韩欧美在线免费观看| 日韩视频免费直播| 青青草免费在线视频观看| 麻豆精品av| 国产精品久久亚洲7777| 一区二区精彩视频| 成人自拍偷拍| 国产中文字幕久久| 手机av在线| 亚洲精品一二区| 色猫av在线| 亚洲午夜激情免费视频| 国产在线你懂得| 中文字幕v亚洲ⅴv天堂| 日本激情视频在线观看| 久久久国产精彩视频美女艺术照福利| 黄色网址免费在线观看| 欧美xxxx18性欧美| 丝袜美女在线观看| 欧美国产日韩一区| а√在线中文在线新版| 青青青国产精品一区二区| 韩国成人在线| 国产情人节一区| 亚洲高清在线一区| 精品无码久久久久久久动漫| 九九热线有精品视频99| 亚洲亚洲精品三区日韩精品在线视频| 91精品国产成人观看| 欧美黑人在线观看| 久久电影一区| 天天综合网久久| 国产成人欧美日韩在线电影| 久久久久麻豆v国产精华液好用吗 在线观看国产免费视频 | 69av.com| 午夜精品免费在线| 国产免费www| 欧美一区二区在线观看| 无码国产色欲xxxx视频| 在线视频欧美日韩精品| 1区2区3区在线视频| 97人人做人人爱| 成人在线高清| 国产区一区二区| 不卡中文一二三区| 狠狠干视频网站| 久久久久国产一区二区| 九九久久久久久| 91视频com| 免费人成在线观看| 欧洲精品在线观看| 亚洲第一天堂影院| 亚洲一区www| 97天天综合网| 国产欧美日韩免费| 久久久久观看| 国产福利片一区二区| 香蕉精品999视频一区二区| 一起草最新网址| 久久久久国产精品人| 久久国产在线视频| 欧美卡1卡2卡| 日本v片在线免费观看| 欧美xxxx18性欧美| 国产黄色精品| 久久亚洲高清| 欧美涩涩视频| 亚洲欧美偷拍另类| 国产日韩影视精品| 国产精品成人网站| 91精品国产色综合久久| 国产youjizz在线| 午夜伦理精品一区| 免费精品一区二区三区在线观看| 日本精品一区二区三区高清 久久| 91久久综合| 天天爽夜夜爽视频| 国产精品久久久久久久久免费相片| 久久久久久久久久久久久久av| 欧美一区二区三区的| av在线播放免费| 青青青国产精品一区二区| 欧美1区二区| 欧美精品久久久久久久自慰| 精品一区二区在线看| 一级黄色片网址| 色欧美乱欧美15图片| 天天综合在线视频| 欧美猛交ⅹxxx乱大交视频| 国产一区二区三区黄网站| 亚洲国产一区二区三区在线| 久久久久久久高潮| 中文精品在线观看| 欧美色视频日本版| 香蕉视频免费看| 2018日韩中文字幕| 天堂俺去俺来也www久久婷婷| 久久久久久久久久伊人| 国产毛片精品视频| 欧美国产在线看| 精品久久人人做人人爱| 色呦呦在线资源| 99视频在线播放| 合欧美一区二区三区| 日韩成人av影院| 亚洲一二三级电影| 蜜臀久久精品久久久久| 午夜精品美女自拍福到在线| 奇米777国产一区国产二区| 内射国产内射夫妻免费频道| 97se亚洲国产综合自在线观| 天天干天天干天天| 国产一区二区日韩| 九九九精品视频| 99精品一区二区三区的区别| 国产精品一区二区久激情瑜伽| 久久国产美女视频| 精品国偷自产国产一区| 日韩欧美精品一区二区三区| 欧美一区二区三区四区夜夜大片| 日韩精品91亚洲二区在线观看| 九九九视频在线观看| 这里只有精品电影| 欧美伦理免费在线| 久久精品午夜一区二区福利| 日韩电影在线一区二区| 欧美肥妇bbwbbw| 亚洲第一免费网站| 外国成人直播| 中文字幕精品在线播放| 99在线视频精品| 波多野结衣家庭主妇| 久久精品国产一区| 精品无人区一区二区| 白嫩少妇丰满一区二区| 亚洲欧洲日产国码二区| 人人妻人人玩人人澡人人爽| 国产xxx69麻豆国语对白| 日韩激情图片| 人妻 丝袜美腿 中文字幕| 福利视频一区二区| 免费在线观看av片| 久久国产精品久久精品国产| 免费成人在线观看视频| 欧美激情一区二区视频| 国产亚洲视频在线观看| 亚洲开心激情| 精品久久久久久中文字幕2017| 亚洲精品成人a在线观看|