成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

這款輕量級(jí)規(guī)則引擎,真香!

開(kāi)發(fā) 前端
在一些輕量級(jí)的需要規(guī)則引擎的場(chǎng)景下,AviatorScript 真的太香了,尤其是它的擴(kuò)展性,支持通過(guò)Java自定義函數(shù),我甚至可以在腳本里查詢數(shù)據(jù)庫(kù)、查詢Redis、調(diào)用外部接口……這樣就可以像搭積木一樣搭建想要的功能。

簡(jiǎn)介

AviatorScript 是一門高性能、輕量級(jí)寄宿于 JVM (包括 Android 平臺(tái))之上的腳本語(yǔ)言。

它起源于2010年,作者對(duì)當(dāng)時(shí)已有的一些產(chǎn)品不是很滿意,所以自己擼了一個(gè),它是Groovy的一個(gè)定制化的子集。

圖片圖片

相比較一些傳統(tǒng)的規(guī)則引擎,比如Drools、Jess、JRules,它更加輕量級(jí),而且性能更好,同時(shí)能力開(kāi)放,擴(kuò)展很方便。

我們來(lái)看(吹)看(吹)AviatorScript的特點(diǎn):

  1. 它支持?jǐn)?shù)字、字符串、正則表達(dá)式、布爾值等基本類型,并且可以使用所有 Java 運(yùn)算符進(jìn)行運(yùn)算。
  2. 還有一個(gè)內(nèi)置的東西叫做 bigint 和 decimal,可以處理超大整數(shù)和高精度運(yùn)算。而且我們還可以通過(guò)運(yùn)算符重載讓它們使用普通的算術(shù)運(yùn)算符 +-*/。
  3. 語(yǔ)法非常齊全,可以用它來(lái)寫多行數(shù)據(jù)、條件語(yǔ)句、循環(huán)語(yǔ)句,還能處理詞法作用域和異常處理等等。
  4. 如果我們喜歡函數(shù)式編程,還有一個(gè)叫做 Sequence 抽象的東西,可以讓你更方便地處理集合。
  5. 還有一個(gè)輕量化的模塊系統(tǒng),方便我們組織代碼。
  6. 如果我們需要調(diào)用 Java 方法,也沒(méi)問(wèn)題,可以用多種方式方便地調(diào)用 Java 方法,還有一個(gè)完整的腳本 API可以讓你從 Java 調(diào)用腳本。
  7. 性能也是超出想象的好,如果使用 ASM 模式,它會(huì)直接將腳本翻譯成 JVM 字節(jié)碼,解釋模式還可以在 Android 等非標(biāo)準(zhǔn) Java 平臺(tái)上運(yùn)行。

AviatorScript可以用在各種場(chǎng)景,比如規(guī)則判斷和規(guī)則引擎、公式計(jì)算、動(dòng)態(tài)腳本控制,甚至集合數(shù)據(jù) ELT 等等。可以說(shuō)相當(dāng)全能了。

快速開(kāi)始

AviatorScript 是一門寄生在 JVM (Hosted on the JVM)上的語(yǔ)言,類似 clojure/scala/kotlin 等等,我們從寫個(gè)Hello World開(kāi)始。

  • 創(chuàng)建一個(gè)SpringBoot項(xiàng)目,引入依賴,這里選擇的是最新版本
<dependency>
            <groupId>com.googlecode.aviator</groupId>
            <artifactId>aviator</artifactId>
            <version>5.3.3</version>
        </dependency>

PS:可以看到aviator的groupId有一個(gè)googlecode,但是它和Google可沒(méi)什么關(guān)系,這是因?yàn)樵缙赼viator托管在Google的一個(gè)開(kāi)源項(xiàng)目托管平臺(tái)Google Code。

  • 在項(xiàng)目的resource目錄下創(chuàng)建一個(gè)目錄script,在script目錄下創(chuàng)建腳本hello.av
println("Hello, AviatorScript!");
  • 編寫一個(gè)單元測(cè)試,運(yùn)行腳本
@Test
    void testHello() throws Exception {
        //獲取路徑
        ClassPathResource resource = new ClassPathResource("script/hello.av");
        String scriptPath = resource.getPath();
        //編譯
        Expression exp = AviatorEvaluator.getInstance().compileScript(scriptPath);
        //執(zhí)行
        exp.execute();
    }

最后執(zhí)行一下,就可以看到輸出:

Hello, AviatorScript!
  • 我們也可以直接把腳本定義成字符串,用compile()來(lái)進(jìn)行編譯
@Test
    void testHelloStr() throws Exception {
        //定義腳本
        String script="println(\"Hello, AviatorScript!\");";
        //編譯
        Expression exp = AviatorEvaluator.getInstance().compile(script);
        //執(zhí)行
        exp.execute();
    }

AviatorScript有一個(gè)Idea插件,支持直接編譯運(yùn)行Aviator腳本,比較方便。

Aviator插件Aviator插件


但不足之處,這個(gè)插件已經(jīng)不怎么維護(hù)了,只兼容到了Idea2021版本。

圖片Idea插件

AviatorScript腳本的運(yùn)行,分為兩步,編譯和執(zhí)行。

編譯執(zhí)行編譯執(zhí)行

編譯支持編譯腳本文件和腳本文本,分別使用compileScript和compile方法。

編譯產(chǎn)生的  Expression 對(duì)象,最終都是調(diào)用 execute() 方法執(zhí)行。

這里有個(gè)重要能力,execute 方法可以接受一個(gè)變量列表組成的 map,來(lái)注入執(zhí)行的上下文:

String expression = "a-(b-c) > 100";
        Expression compiledExp = AviatorEvaluator.compile(expression);
        //上下文
        double a=100.3,b=45,c= -199.100;
        Map<String, Object> cnotallow=new HashMap<>();
        context.put("a",a);
        context.put("b",b);
        context.put("c",c);
        //通過(guò)注入的上下文執(zhí)行
        Boolean result = (Boolean) compiledExp.execute(context);
        System.out.println(result);

我們實(shí)現(xiàn)一些規(guī)則的判斷就是基于這個(gè)能力,把一些參數(shù)下上下文傳進(jìn)去,然后進(jìn)行邏輯判斷。

基本語(yǔ)法

我們?cè)趤?lái)看看AviatorScript的基本語(yǔ)法,它的語(yǔ)法相當(dāng)簡(jiǎn)潔,比較接近于數(shù)學(xué)表達(dá)式的形式。

基本類型及運(yùn)算

AviatorScript 支持常見(jiàn)的類型,如數(shù)字、布爾值、字符串等等,同時(shí)將大整數(shù)、BigDecimal、正則表達(dá)式也作為一種基本類型來(lái)支持。

數(shù)字

AviatorScript 支持?jǐn)?shù)字類型,包括整數(shù)和浮點(diǎn)數(shù),以及高精度計(jì)算(BigDecimal)。數(shù)字類型可以進(jìn)行各種算術(shù)運(yùn)算。

整數(shù)和算術(shù)運(yùn)算

整數(shù)類型,對(duì)應(yīng)Java中的long類型,可以表示范圍為 -9223372036854774808 ~ 9223372036854774807 的整數(shù)。整數(shù)可以使用十進(jìn)制或十六進(jìn)制表示。

let a = 99;
let b = 0xFF;
let c = -99;

println(a + b); // 270
println(a / b); // 0
println(a - b + c); // -156
println(a + b * c); // -9801
println(a - (b - c)); // 198
println(a / b * b + a % b); // 99

整數(shù)可以進(jìn)行加減乘除和取模運(yùn)算。需要注意的是,整數(shù)相除的結(jié)果仍然是整數(shù),遵循整數(shù)運(yùn)算規(guī)則。可以使用括號(hào)來(lái)指定運(yùn)算的優(yōu)先級(jí)。

浮點(diǎn)數(shù)

浮點(diǎn)數(shù)類型對(duì)應(yīng)Java中的double類型,表示雙精度 64 位浮點(diǎn)數(shù)。浮點(diǎn)數(shù)可以使用十進(jìn)制或科學(xué)計(jì)數(shù)法表示。

let a = 1.34159265;
let b = 0.33333;
let c = 1e-2;

println(a + b); // 1.67492265
println(a - b); // 1.00826265
println(a * b); // 0.4471865500145
println(a / b); // 4.0257402772554
println(a + c); // 1.35159265

浮點(diǎn)數(shù)可以進(jìn)行加減乘除運(yùn)算,結(jié)果仍然為浮點(diǎn)數(shù)。

高精度計(jì)算(Decimal)

高精度計(jì)算使用 BigDecimal 類型,可以進(jìn)行精確的數(shù)值計(jì)算,適用于貨幣運(yùn)算或者物理公式運(yùn)算的場(chǎng)景。可以通過(guò)在數(shù)字后面添加 "M" 后綴來(lái)表示 BigDecimal 類型。

let a = 1.34M;
let b = 0.333M;
let c = 2e-3M;

println(a + b); // 1.673M
println(a - b); // 1.007M
println(a * b); // 0.44622M
println(a / b); // 4.022022022M
println(a + c); // 1.342M

BigDecimal 類型可以進(jìn)行加減乘除運(yùn)算,結(jié)果仍然為 BigDecimal 類型。默認(rèn)的運(yùn)算精度是 MathContext.DECIMAL128,可以通過(guò)修改引擎配置項(xiàng) Options.MATH_CONTEXT 來(lái)改變。

數(shù)字類型轉(zhuǎn)換

數(shù)字類型在運(yùn)算時(shí)會(huì)自動(dòng)進(jìn)行類型轉(zhuǎn)換:

  • 單一類型參與的運(yùn)算,結(jié)果仍然為該類型。
  • 多種類型參與的運(yùn)算,按照 long -> bigint -> decimal -> double 的順序自動(dòng)提升,結(jié)果為提升后的類型。

可以使用 long(x) 函數(shù)將數(shù)字強(qiáng)制轉(zhuǎn)換為 long 類型,使用 double(x) 函數(shù)將數(shù)字強(qiáng)制轉(zhuǎn)換為 double 類型。

let a = 1;
let b = 2;

println("a/b is " + a/b); // 0
println("a/double(b) is " + a/double(b)); // 0.5

a 和 b 都是 long 類型,它們相除的結(jié)果仍然是整數(shù)。使用 double(b) 將 b 轉(zhuǎn)換為 double 類型后,相除的結(jié)果為浮點(diǎn)數(shù)。

字符串

字符串類型由單引號(hào)或雙引號(hào)括起來(lái)的連續(xù)字符組成。可以使用 println 函數(shù)來(lái)打印字符串。

let a = "hello world";
println(a); // hello world

字符串的長(zhǎng)度可以通過(guò) string.length 函數(shù)獲取。

let a = "hello world";
println(string.length(a)); // 11

字符串可以通過(guò) + 運(yùn)算符進(jìn)行拼接。

let a = "hello world";
let b = "AviatorScript";
println(a + ", " + b + "!" + 5); // hello world, AviatorScript!5

字符串還包括其他函數(shù),如截取字符串 substring,都在 string 這個(gè) namespace 下,具體見(jiàn)函數(shù)庫(kù)列表。

布爾類型和邏輯運(yùn)算

布爾類型用于表示真和假,它只有兩個(gè)值 true 和 false 分別表示真值和假值。

比較運(yùn)算如大于、小于可以產(chǎn)生布爾值:

println("3 > 1 is " + (3 > 1));  // 3 > 1 is true
println("3 >= 1 is " + (3 >= 1));  // 3 >= 1 is true
println("3 >= 3 is " + (3 >= 3));  // 3 >= 3 is true
println("3 < 1 is " + (3 < 1));  // 3 < 1 is false
println("3 <= 1 is " + (3 <= 1));  // 3 <= 1 is false
println("3 <= 3 is " + (3 <= 3));  // 3 <= 3 is true
println("3 == 1 is " + (3 == 1));  // 3 == 1 is false
println("3 != 1 is " + (3 != 1));  // 3 != 1 is true

上面演示了所有的邏輯運(yùn)算符:

  • > 大于
  • >= 大于等于
  • < 小于
  • <= 小于等于
  • == 等于
  • != 不等于

基本語(yǔ)法

AviatorScript也支持條件語(yǔ)句和循環(huán)語(yǔ)句。

條件語(yǔ)句

AviatorScript 中的條件語(yǔ)句和其他語(yǔ)言沒(méi)有太大區(qū)別:

  • if
if(true) {
   println("in if body");
}
  • if-else
if(false){
   println("in if body");
} else {
   println("in else body");
}
  • if-elsif-else
let a = rand(1100);

if(a > 1000) {
  println("a is greater than 1000.");
} elsif (a > 100) {
  println("a is greater than 100.");
} elsif (a > 10) {
   println("a is greater than 10.");
} else {
   println("a is less than 10 ");
}

循環(huán)語(yǔ)句

AviatorScript提供了兩種循環(huán)語(yǔ)句:for和while。

for循環(huán):遍歷集合

for ... in 語(yǔ)句通常用于遍歷一個(gè)集合,例如下面是遍歷 0 到 9 的數(shù)字

for i in range(0, 10) {
  println(i);
}

在這里,range(start, end) 函數(shù)用于創(chuàng)建一個(gè)整數(shù)集合,包括起始值 start,但不包括結(jié)束值 end。在循環(huán)迭代過(guò)程中,變量 i 綁定到集合中的每個(gè)元素,并執(zhí)行大括號(hào) {...} 中的代碼塊。

range 函數(shù)還可以接受第三個(gè)參數(shù),表示遞增的步長(zhǎng)大小(默認(rèn)步長(zhǎng)為 1)。例如,我們可以打印出0到9之間的偶數(shù):

for i in range(0, 10, 2) {
  println(i);
}

for .. in 可以用于任何集合結(jié)構(gòu),比如數(shù)組、 java.util.List 、 java.util.Map 等等。

while循環(huán)

while 循環(huán)本質(zhì)上是將條件語(yǔ)句與循環(huán)結(jié)合在一起。當(dāng)條件為真時(shí),不斷執(zhí)行一段代碼塊,直到條件變?yōu)榧佟?/p>

例如,下面的示例中,變量 sum 從 1 開(kāi)始,不斷累加自身,直到超過(guò) 1000 才停止,然后進(jìn)行打印輸出:

let sum = 1;

while sum < 1000 {
  sum = sum + sum;
}

println(sum);

循環(huán)可以用這三個(gè)關(guān)鍵字結(jié)束——continue/break/return:

  • continue用于跳過(guò)當(dāng)前迭代,繼續(xù)下一次迭代。
  • break用于跳出整個(gè)循環(huán)。
  • return用于中斷整個(gè)腳本(或函數(shù))的執(zhí)行并返回。

函數(shù)

我們?cè)賮?lái)看看AviatorScript一個(gè)非常重要的特性——函數(shù)。

函數(shù)

函數(shù)定義和調(diào)用

AviatorScript中使用fn語(yǔ)法來(lái)定義函數(shù):

fn add(x, y) {
  return x + y;
}

three = add(1, 2);
println(three);  // 輸出:3

s = add('hello', ' world');
println(s);  // 輸出:hello world

我們這里通過(guò)fn關(guān)鍵字來(lái)定義了一個(gè)函數(shù),函數(shù)名為add,它接受兩個(gè)參數(shù)x和y,并返回它們的和。

需要注意的是,AviatorScript是動(dòng)態(tài)類型系統(tǒng),不需要定義參數(shù)和返回值的類型,它會(huì)根據(jù)實(shí)際傳入和返回的值進(jìn)行自動(dòng)類型轉(zhuǎn)換。因此,我們可以使用字符串來(lái)調(diào)用add函數(shù)。

函數(shù)的返回值可以通過(guò)return語(yǔ)句來(lái)指定,也可以省略不寫。在函數(shù)體內(nèi),如果沒(méi)有明確的return語(yǔ)句,最后一個(gè)表達(dá)式的值將被作為返回值。

自定義函數(shù)

再來(lái)給大家介紹一個(gè)AviatorScript里非常好的特性,支持自定義函數(shù),這給AviatorScript帶來(lái)了非常強(qiáng)的擴(kuò)展性。

可以通過(guò) java 代碼實(shí)現(xiàn)并往引擎中注入自定義函數(shù),在 AviatorScript 中就可以使用,事實(shí)上所有的內(nèi)置函數(shù)也是通過(guò)同樣的方式實(shí)現(xiàn)的:

public class TestAviator {

    public static void main(String[] args) {
        //通通創(chuàng)建一個(gè)AviatorEvaluator的實(shí)例
        AviatorEvaluatorInstance instance = AviatorEvaluator.getInstance();
        //注冊(cè)函數(shù)
        instance.addFunction(new AddFunction());
        //執(zhí)行ab腳本,腳本里調(diào)用自定義函數(shù)
        Double result= (Double) instance.execute("add(1, 2)");
        //輸出結(jié)果
        System.out.println(result);
    }
}

/**
 * 實(shí)現(xiàn)AbstractFunction接口,就可以自定義函數(shù)
 */
class AddFunction extends AbstractFunction {

    /**
     * 函數(shù)調(diào)用
     * @param env 當(dāng)前執(zhí)行的上下文
     * @param arg1 第一個(gè)參數(shù)
     * @param arg2 第二個(gè)參數(shù)
     * @return 函數(shù)返回值
     */
    @Override
    public AviatorObject call(Map<String, Object> env,
                              AviatorObject arg1, AviatorObject arg2) {
        Number left = FunctionUtils.getNumberValue(arg1, env);
        Number right = FunctionUtils.getNumberValue(arg2, env);
        //將兩個(gè)參數(shù)進(jìn)行相加
        return new AviatorDouble(left.doubleValue() + right.doubleValue());
    }

    /**
     * 函數(shù)的名稱
     * @return 函數(shù)名
     */
    public String getName() {
        return "add";
    }
}

我們看到:

  • 繼承AbstractFunction類,就可以自定義一個(gè)函數(shù)
  • 重寫call方法,就可以定義函數(shù)的邏輯,可以通過(guò)FunctionUtils獲取腳本傳遞的參數(shù)
  • 通過(guò)getName可以設(shè)置函數(shù)的名稱
  • 通過(guò)addFunction添加一個(gè)自定義函數(shù)類的實(shí)例,就可以注冊(cè)函數(shù)
  • 最后就可以在Aviator的腳本里編譯執(zhí)行我們自定義的函數(shù)

好了,關(guān)于AviatorScript的語(yǔ)法我們就不過(guò)多介紹了,大家可以直接查看官方文檔[1],可讀性相當(dāng)不錯(cuò)。

接下來(lái)我們就來(lái)看看AviatorScript的實(shí)際應(yīng)用,看看它到底怎么提升項(xiàng)目的靈活性。

實(shí)戰(zhàn)案例

標(biāo)題帶了規(guī)則引擎,在我們的項(xiàng)目里也主要是拿AviatorScript作為規(guī)則引擎使用——我們可以把AviatorScript的腳本維護(hù)在配置中心或者數(shù)據(jù)庫(kù),進(jìn)行動(dòng)態(tài)地維護(hù),這樣一來(lái),一些規(guī)則的修改,就不用大動(dòng)干戈地去修改代碼,這樣就更加方便和靈活了。

圖片圖片

Aviator應(yīng)用

客戶端版本控制

在日常的開(kāi)發(fā)中,我們很多時(shí)候可能面臨這樣的情況,兼容客戶端的版本,尤其是Android和iPhone,有些功能是低版本不支持的,或者說(shuō)有些功能到了高版本就廢棄掉,這時(shí)候如果硬編碼去兼容就很麻煩,那么就可以考慮使用規(guī)則腳本的方式。

  • 自定義版本比較函數(shù):AviatorScript沒(méi)有內(nèi)置版本比較函數(shù),但是可以利用它的自定義函數(shù)特性,自己定義一個(gè)版本比較函數(shù)
class VersionFunction extends AbstractFunction {

        @Override
        public String getName() {
            return "compareVersion";
        }

        @Override
        public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2) {
            // 獲取版本
            String version1 = FunctionUtils.getStringValue(arg1, env);
            String version2 = FunctionUtils.getStringValue(arg2, env);
            int n = version1.length(), m = version2.length();
            int i = 0, j = 0;
            while (i < n || j < m) {
                int x = 0;
                for (; i < n && version1.charAt(i) != '.'; ++i) {
                    x = x * 10 + version1.charAt(i) - '0';
                }
                ++i; // 跳過(guò)點(diǎn)號(hào)
                int y = 0;
                for (; j < m && version2.charAt(j) != '.'; ++j) {
                    y = y * 10 + version2.charAt(j) - '0';
                }
                ++j; // 跳過(guò)點(diǎn)號(hào)
                if (x != y) {
                    return x > y ? new AviatorBigInt(1) : new AviatorBigInt(-1);
                }
            }
            return new AviatorBigInt(0);
        }
    }
  • 注冊(cè)自定義函數(shù):為了方便使用各種自定義函數(shù),我們一般定義一個(gè)單例的AviatorEvaluatorInstance,把它注冊(cè)成Bean
@Bean
    public AviatorEvaluatorInstance aviatorEvaluatorInstance() {
        AviatorEvaluatorInstance instance = AviatorEvaluator.getInstance();
        // 默認(rèn)開(kāi)啟緩存
        instance.setCachedExpressionByDefault(true);
        // 使用LRU緩存,最大值為100個(gè)。
        instance.useLRUExpressionCache(100);
        // 注冊(cè)內(nèi)置函數(shù),版本比較函數(shù)。
        instance.addFunction(new VersionFunction());
    }
  • 在代碼里傳遞上下文:接下來(lái),就可以在業(yè)務(wù)代碼里將一些參數(shù)放進(jìn)執(zhí)行上下文,然然后進(jìn)行編譯執(zhí)行,注意編譯的時(shí)候最好要開(kāi)啟緩存,這樣效率會(huì)高很多
/**
     * 
     * @param device 設(shè)備
     * @param version 版本
     * @param rule 規(guī)則腳本
     * @return
     */
    public boolean filter(String device,String version,String rule){
        // 執(zhí)行參數(shù)
        Map<String, Object> env = new HashMap<>();
        env.put("device", device);
        //編譯腳本
        Expression expression = aviatorEvaluatorInstance.compile(DigestUtils.md5DigestAsHex(rule.getBytes()), rule, true);
        //執(zhí)行腳本
        boolean isMatch = (boolean) expression.execute(env);
        return isMatch;
    }
  • 編寫腳本:接下來(lái)就可以編寫和維護(hù)對(duì)應(yīng)的規(guī)則腳本,這些規(guī)則腳本通常放在在配置中心或者數(shù)據(jù)庫(kù),方便進(jìn)行動(dòng)態(tài)變更
if(device==bil){
    return false;
}

## 控制android的版本
if (device=="Android" && compareVersion(version,"1.38.1")<0){
    return false;
}

return true;

這樣一來(lái),假如某天,客戶端Bug或者產(chǎn)品原因,需要修改客戶端和客戶端的版本控制,直接修改腳本就好了。

甚至我們可以在env里放進(jìn)更多參數(shù),比如uid,可以實(shí)現(xiàn)簡(jiǎn)單的黑白名單。

我們的自定義函數(shù)除了這種簡(jiǎn)單的比較版本,我們還可以放一些復(fù)雜的邏輯,比如判斷是否新用戶等等。

營(yíng)銷活動(dòng)規(guī)則

假如現(xiàn)在我們的運(yùn)營(yíng)希望進(jìn)行一場(chǎng)營(yíng)銷活動(dòng),對(duì)用戶進(jìn)行一定的支付優(yōu)惠,最開(kāi)始的一版活動(dòng)規(guī)則:

  • 滿1000減200,滿500減100

這個(gè)好寫,一頓if-else就完事了。

但是沒(méi)過(guò)幾天,又改了活動(dòng)規(guī)則:

  • 首單用戶統(tǒng)一減20

好,啪啪改代碼。

又過(guò)去幾天,活動(dòng)規(guī)則又改了:

  • 隨機(jī)優(yōu)惠不同金額

為了一些多變的營(yíng)銷規(guī)則,大動(dòng)干戈,不停修改代碼,耗時(shí)費(fèi)力,那么不如用規(guī)則腳本實(shí)現(xiàn):

  • 定義腳本
if (amount>=100){
    return 200;
}elsif(amount>=500){
    return 100;
}else{
    return 0;
}
  • 業(yè)務(wù)代碼調(diào)用
public BigDecimal getDiscount(BigDecimal amount,String rule){
        // 執(zhí)行規(guī)則并計(jì)算最終價(jià)格
        Map<String, Object> env = new HashMap<>();
        env.put("amount", amount);
        Expression expression = aviatorEvaluatorInstance.compile(DigestUtils.md5DigestAsHex(rule.getBytes()), rule, true);
        return  (BigDecimal) expression.execute();
    }

接下來(lái),再發(fā)生營(yíng)銷規(guī)則變更,就可以少量開(kāi)發(fā)(自定義函數(shù),比如判斷首單用戶),并且可以組件化地維護(hù)營(yíng)銷規(guī)則。

訂單風(fēng)控規(guī)則

Aviator我在訂單風(fēng)控里應(yīng)用也很香,風(fēng)控的規(guī)則調(diào)整是相當(dāng)頻繁的,比如一個(gè)電商網(wǎng)站,常常要根據(jù)交易的爭(zhēng)議率、交易表現(xiàn)等等,來(lái)收緊和放松風(fēng)控規(guī)則,這就要求我們能對(duì)一風(fēng)控規(guī)則進(jìn)行快速地配置變更。

例如,根據(jù)訂單金額、客戶評(píng)級(jí)、收貨地址等屬性,自動(dòng)判斷是否有風(fēng)險(xiǎn)并觸發(fā)相應(yīng)的風(fēng)控操作。

  • 規(guī)則腳本
if (amount>=1000 || rating <= 2){
    return "High";
}elsif(amount >= 500 || rating<=4){
    return "Mid";
}else{
    return "Low";
}
  • 代碼調(diào)用:這里只是簡(jiǎn)單返回了一個(gè)風(fēng)控等級(jí),其實(shí)可以通過(guò)Map的方式返回多個(gè)參數(shù)。
public String riskLevel(BigDecimal amount,String rating,String rule){
        // 執(zhí)行規(guī)則并計(jì)算最終價(jià)格
        Map<String, Object> env = new HashMap<>();
        env.put("amount", amount);
        env.put("rating", rating);
        Expression expression = aviatorEvaluatorInstance.compile(DigestUtils.md5DigestAsHex(rule.getBytes()), rule, true);
        return  (String) expression.execute();
    }

上面隨手列出了幾個(gè)簡(jiǎn)單的例子,AviatorScript 還可以用在一些審批流程、事件處理、數(shù)據(jù)質(zhì)量管理等等場(chǎng)景……

在一些輕量級(jí)的需要規(guī)則引擎的場(chǎng)景下,AviatorScript 真的太香了,尤其是它的擴(kuò)展性,支持通過(guò)Java自定義函數(shù),我甚至可以在腳本里查詢數(shù)據(jù)庫(kù)、查詢Redis、調(diào)用外部接口……這樣就可以像搭積木一樣搭建想要的功能。

總結(jié)

這一期給大家分享了一款輕量級(jí)的規(guī)則腳本語(yǔ)言AviatorScript,它的語(yǔ)法豐富,但是很輕量,并且支持非常靈活的擴(kuò)展,在項(xiàng)目中使用可以有效提高業(yè)務(wù)的靈活性,降低開(kāi)發(fā)的工作量。

  1. 本來(lái)這期想淺淺盤點(diǎn)一下AviatorScript的設(shè)計(jì)實(shí)現(xiàn),結(jié)果發(fā)現(xiàn)越盤越深,所以就單獨(dú)拆出來(lái),放在下一期了,敬請(qǐng)期待。
責(zé)任編輯:武曉燕 來(lái)源: 三分惡
相關(guān)推薦

2025-05-13 04:15:00

2024-11-13 16:32:21

aviatorJava表達(dá)式引擎

2023-11-01 11:04:12

Javaaviator

2025-02-19 09:55:39

2025-06-23 00:00:05

2022-03-22 09:20:57

應(yīng)用線程池技術(shù)

2022-09-05 09:37:38

Linux發(fā)行版

2024-02-26 07:46:54

Markdown語(yǔ)法標(biāo)記語(yǔ)言有序列表

2019-05-07 14:42:03

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

2025-06-09 02:11:00

2025-03-18 14:33:14

2009-07-14 18:05:28

輕量級(jí)Swing組件

2009-07-17 14:38:51

輕量級(jí)Swing組件

2025-03-05 09:30:00

小模型CIO智能化轉(zhuǎn)型

2016-10-14 16:35:39

2009-09-11 08:26:49

Linux系統(tǒng)CRUX 2.6Linux

2021-03-02 09:35:33

Python循環(huán)開(kāi)發(fā)

2023-06-27 16:42:18

Tinygrad深度學(xué)習(xí)工具

2023-09-14 09:31:21

Docker容器

2022-03-14 08:02:08

輕量級(jí)動(dòng)態(tài)線程池
點(diǎn)贊
收藏

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

主站蜘蛛池模板: 久草免费在线视频 | 91在线视频一区 | 国产视频精品区 | 在线播放亚洲 | 日本免费在线 | 一级黄色片免费 | 91短视频网址 | 国产一级视频在线播放 | 欧美日韩高清在线一区 | 精品国产精品国产偷麻豆 | 91性高湖久久久久久久久_久久99 | 久久精品亚洲精品 | 日韩福利在线 | 一区二区三区欧美 | 国产精品美女久久久久久久久久久 | 成人欧美一区二区三区 | 国产一区在线免费 | 亚洲精品国产电影 | 日韩视频精品在线 | 高清免费av | 欧美一区二区三区 | 中文字幕在线视频免费观看 | 国产精品久久久久久久久久免费 | 成人免费影院 | 精品国产乱码久久久久久影片 | 亚洲综合一区二区三区 | 精品少妇一区二区三区日产乱码 | 男女深夜网站 | 久久丁香| 在线观看日本网站 | 天天夜天天操 | 亚洲精品电影网在线观看 | 韩日一区 | 看av网| 中文字幕一区二区三区四区五区 | 欧美亚洲国产日韩 | 免费高清成人 | 精品一区在线看 | 成人免费在线观看 | 日韩中文字幕一区 | 羞羞视频网站免费观看 |