自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

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

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

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

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

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

一、QLExpress快速了解

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

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

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

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

圖片圖片

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

三、快速引用和一般工作原理簡(jiǎn)訴

1.引用與基本演示

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

<dependencies>
    <dependency>
        <groupId>com.ql</groupId>
        <artifactId>qlExpress</artifactId>
        <version>3.2.2</version> <!-- 使用實(shí)際版本號(hào) -->
    </dependency>
</dependencies>

以下展示簡(jiǎn)單演示如何使用 QLExpress 計(jì)算折扣后的金額。在實(shí)際項(xiàng)目中,可能需要更復(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 計(jì)算折扣后的金額
 * @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.一般工作原理說(shuō)明

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

圖片圖片

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

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

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

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

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

1.操作符

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

圖片圖片

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

package org.zyf.javabasic.qlexpress;

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

/**
 * @program: zyfboot-javabasic
 * @description: 一些簡(jiǎn)單的運(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對(duì)象操作

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

package org.zyf.javabasic.qlexpress;

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

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

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

            // 使用 Java 語(yǔ)法訪(fǎng)問(wèn)對(duì)象屬性和調(diào)用方法
            executeAndPrint(runner, context, "user.getName()", "Accessing Object Property");
            executeAndPrint(runner, context, "user.getAge() + 5", "Performing Arithmetic with Object Property");

            // 使用 Java 語(yǔ)法進(jìn)行對(duì)象操作
            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);
    }

    // 用戶(hù)對(duì)象類(lèi)
    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中,可以通過(guò) function 關(guān)鍵字來(lái)定義函數(shù)。以下是一個(gè)簡(jiǎn)單的示例:

package org.zyf.javabasic.qlexpress;

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

/**
 * @program: zyfboot-javabasic
 * @description: 通過(guò) function 關(guān)鍵字來(lái)定義函數(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)用過(guò)程中的參數(shù)和返回值
            System.out.println("add function call: a + 4 = " + context.get("a") + " + 4 = " + context.get("result"));

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

4.擴(kuò)展操作符

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

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)來(lái)擴(kuò)展語(yǔ)言的功能
 * @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("語(yǔ)文",120);
            context1.put("數(shù)學(xué)",23);
            context1.put("英語(yǔ)",23);

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

            String express1 = "如果 (語(yǔ)文 + 數(shù)學(xué) + 英語(yǔ) > 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 類(lèi)的定義
    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類(lèi)或?qū)ο蟮膍ethon

在 QLExpress 中,可使用 addFunctionOfClassMethod 和 addFunctionOfServiceMethod 方法來(lái)綁定 Java 類(lèi)或?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 方法來(lái)綁定 Java 類(lèi)或?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 類(lèi)的 abs 方法
            runner.addFunctionOfClassMethod("取絕對(duì)值", Math.class.getName(), "abs", new String[]{"double"}, null);

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

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

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

            String express = "取絕對(duì)值(-100); 轉(zhuǎn)換為大寫(xiě)(\"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("取絕對(duì)值結(jié)果: " + value);
            return Math.abs(value);
        }

        public static String upper(String abc) {
            System.out.println("轉(zhuǎn)換為大寫(xiě)結(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)允許將一個(gè)表達(dá)式片段命名為宏,并在其他地方引用這個(gè)宏。當(dāng)需要在多個(gè)地方使用相同的復(fù)雜表達(dá)式時(shí)非常有用,可以提高代碼的可讀性和維護(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("計(jì)算平均成績(jī)", "(語(yǔ)文+數(shù)學(xué)+英語(yǔ))/3.0");
            runner.addMacro("是否優(yōu)秀", "計(jì)算平均成績(jī)>90");

            // 設(shè)置變量值
            context.put("語(yǔ)文", 88);
            context.put("數(shù)學(xué)", 99);
            context.put("英語(yǔ)", 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.編譯腳本查詢(xún)外部需要定義的變量和函數(shù)

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

package org.zyf.javabasic.qlexpress;

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

/**
 * @program: zyfboot-javabasic
 * @description: 編譯腳本,查詢(xún)外部需要定義的變量和函數(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("語(yǔ)文",120);
            context.put("數(shù)學(xué)",23);
            context.put("英語(yǔ)",23);
            context.put("綜合考試",235);

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

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

            // 查詢(xún)外部需要定義的函數(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();
        }
    }
}

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

執(zhí)行的表達(dá)式:double 平均分 = (語(yǔ)文 + 數(shù)學(xué) + 英語(yǔ) + 綜合考試) / 4.0; return 平均分
單詞分解結(jié)果:{double},{平均分},{=},{(},{語(yǔ)文},{+},{數(shù)學(xué)},{+},{英語(yǔ)},{+},{綜合考試},{)},{/},{4.0},{;},{return},{平均分}
預(yù)處理后結(jié)果:{double},{平均分},{=},{(},{語(yǔ)文},{+},{數(shù)學(xué)},{+},{英語(yǔ)},{+},{綜合考試},{)},{/},{4.0},{;},{return},{平均分}
單詞分析結(jié)果:double:CONST_CLASS,平均分:ID,=:=,(:(,語(yǔ)文:ID,+:+,數(shù)學(xué):ID,+:+,英語(yǔ):ID,+:+,綜合考試:ID,):),/:/,4.0:CONST_DOUBLE,;:;,return:return,平均分:ID
最后的語(yǔ)法樹(shù):
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:                           語(yǔ)文:ID ID
9:                           數(shù)學(xué):ID ID
8:                        英語(yǔ):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:語(yǔ)文
5:LoadAttr:數(shù)學(xué)
6:OP : + OPNUMBER[2]
7:LoadAttr:英語(yǔ)
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 : 英語(yǔ)
var : 語(yǔ)文
執(zhí)行的表達(dá)式:double 平均分 = (語(yǔ)文 + 數(shù)學(xué) + 英語(yǔ) + 綜合考試) / 4.0; return 平均分
單詞分解結(jié)果:{double},{平均分},{=},{(},{語(yǔ)文},{+},{數(shù)學(xué)},{+},{英語(yǔ)},{+},{綜合考試},{)},{/},{4.0},{;},{return},{平均分}
預(yù)處理后結(jié)果:{double},{平均分},{=},{(},{語(yǔ)文},{+},{數(shù)學(xué)},{+},{英語(yǔ)},{+},{綜合考試},{)},{/},{4.0},{;},{return},{平均分}
單詞分析結(jié)果:double:CONST_CLASS,平均分:ID,=:=,(:(,語(yǔ)文:ID,+:+,數(shù)學(xué):ID,+:+,英語(yǔ):ID,+:+,綜合考試:ID,):),/:/,4.0:CONST_DOUBLE,;:;,return:return,平均分:ID
最后的語(yǔ)法樹(shù):
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:                           語(yǔ)文:ID ID
9:                           數(shù)學(xué):ID ID
8:                        英語(yǔ):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:語(yǔ)文
5:LoadAttr:數(shù)學(xué)
6:OP : + OPNUMBER[2]
7:LoadAttr:英語(yǔ)
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 平均分 = (語(yǔ)文 + 數(shù)學(xué) + 英語(yǔ) + 綜合考試) / 4.0; return 平均分
單詞分解結(jié)果:{double},{平均分},{=},{(},{語(yǔ)文},{+},{數(shù)學(xué)},{+},{英語(yǔ)},{+},{綜合考試},{)},{/},{4.0},{;},{return},{平均分}
預(yù)處理后結(jié)果:{double},{平均分},{=},{(},{語(yǔ)文},{+},{數(shù)學(xué)},{+},{英語(yǔ)},{+},{綜合考試},{)},{/},{4.0},{;},{return},{平均分}
單詞分析結(jié)果:double:CONST_CLASS,平均分:ID,=:=,(:(,語(yǔ)文:ID,+:+,數(shù)學(xué):ID,+:+,英語(yǔ):ID,+:+,綜合考試:ID,):),/:/,4.0:CONST_DOUBLE,;:;,return:return,平均分:ID
最后的語(yǔ)法樹(shù):
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:                           語(yǔ)文:ID ID
9:                           數(shù)學(xué):ID ID
8:                        英語(yǔ):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:語(yǔ)文
5:LoadAttr:數(shù)學(xué)
6:OP : + OPNUMBER[2]
7:LoadAttr:英語(yǔ)
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中,可以通過(guò)使用不定參數(shù)(動(dòng)態(tài)參數(shù))來(lái)處理方法的參數(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 實(shí)例
            ExpressRunner runner = new ExpressRunner();

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

            // 在 runner 中添加一個(gè)函數(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);

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

            // 調(diào)用 getTemplate 方法,傳遞多個(gè)參數(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();
        }
    }

    // 等價(jià)于 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中,你可以使用一些快捷的語(yǔ)法來(lái)操作集合。

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);

            // 使用方括號(hào)[]創(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.集合的遍歷

類(lèi)似java的語(yǔ)法,只是ql不支持for(obj:list){}的語(yǔ)法,只能通過(guò)下標(biāo)訪(fǎng)問(wèn)。

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)建一個(gè)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 作為阿里巴巴開(kāi)源的一款輕量級(jí)動(dòng)態(tài)腳本引擎的主要功能和應(yīng)用場(chǎng)景,并深入講解了其在規(guī)則引擎和業(yè)務(wù)場(chǎng)景中的使用優(yōu)勢(shì)。通過(guò)對(duì)比其他規(guī)則引擎的性能與靈活性,QLExpress 展現(xiàn)了其在處理動(dòng)態(tài)規(guī)則、復(fù)雜計(jì)算邏輯、實(shí)時(shí)決策等方面的獨(dú)特優(yōu)勢(shì),尤其適用于需要?jiǎng)討B(tài)配置業(yè)務(wù)規(guī)則的場(chǎng)景。在實(shí)際應(yīng)用中,QLExpress 的簡(jiǎn)潔語(yǔ)法、快速上手和高性能表現(xiàn),使其成為了企業(yè)動(dòng)態(tài)業(yè)務(wù)處理的有效工具。

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

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

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

2025-02-04 11:30:10

2023-10-31 12:42:00

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

2025-02-07 08:16:26

Java開(kāi)發(fā)者代碼

2022-03-23 15:19:00

低代碼開(kāi)源阿里巴巴

2023-08-09 08:01:38

場(chǎng)景Redis接口

2015-09-28 14:27:12

硬編默認(rèn)選擇

2022-12-19 08:32:57

項(xiàng)目Feign框架

2019-05-07 14:42:03

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

2021-01-18 06:43:54

程序員公務(wù)員996

2018-12-17 09:57:11

服務(wù)器LinuxBoot開(kāi)源

2022-03-21 08:30:13

開(kāi)源模型訓(xùn)練預(yù)測(cè)引擎

2021-06-11 10:53:40

Folly組件開(kāi)發(fā)

2024-12-26 00:14:45

C#腳本開(kāi)源

2020-12-30 09:33:37

開(kāi)源茅臺(tái)神器

2016-05-18 09:52:20

2024-10-25 11:56:33

OCRVisRAGRAG

2016-12-15 14:13:16

Java 8Nashorn腳本

2021-01-28 10:23:26

Seata模式分布式

2018-10-18 11:20:06

編程語(yǔ)言代碼編碼秘訣

2014-03-26 15:08:33

Java 8腳本引擎
點(diǎn)贊
收藏

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