Aviator表達(dá)式快速上手

遇到的問題

最近項(xiàng)目中有這樣一種場景:需要改變部分訂單的結(jié)算方式,這個(gè)改動點(diǎn)對交易結(jié)算影響很大,需要逐步切流以減少風(fēng)險(xiǎn)。訂單有buyerId(買家id)、sellerId(賣家id)、tkBizTag(訂單打標(biāo))……幾十個(gè)字段,如果case by case硬編碼來限定切流的場景來做,就很不靈活,單純這個(gè)切流就要上多次線。
因此有這樣的技術(shù)需求:使用一種靈活多變的切流方式,即可支持對按照訂單對象任何一個(gè)參數(shù)滿足某種條件時(shí)進(jìn)行切流,如按照訂單類型字段、某些買家id符合要求。

解決方案

經(jīng)過調(diào)研,最終采用aviator表達(dá)式+動態(tài)內(nèi)容推送中間件(diamond)來實(shí)現(xiàn)。
一個(gè)簡單的demo如下:

NCpsPaymentDTO paymentDTO = newNCpsPaymentDTO();
paymentDTO.setTkBizTag(5);
paymentDTO.setTbBuyerId(1234L);
ExtraInfo extraInfo = new ExtraInfo();
extraInfo.setEventId(1234567L);
HashMap paramMap= new HashMap();
paramMap.put("paymentDTO",paymentDTO);
paramMap.put("extraInfo",extraInfo);
String configInfo ="paymentDTO.tkBizTag == 5 && paymentDTO.tbBuyerId % 10000 <=2000 && extraInfo.eventId == 1234567";
Expression expression =AviatorEvaluator.compile(configInfo);
Boolean rst = (Boolean)expression.execute(paramMap);
System.out.println(rst);//true

Note:
其中configInfo取自動態(tài)內(nèi)容推送中間件diamond,可以根據(jù)需求隨時(shí)更新并推送到各臺線上機(jī)器。

了解到這個(gè)程度足夠了么?No.關(guān)于aviator還需要知道得更多。

Aviator簡介

Aviator是一個(gè)高性能、輕量級的java語言實(shí)現(xiàn)的表達(dá)式求值引擎,主要用于各種表達(dá)式的動態(tài)求值。現(xiàn)在已經(jīng)有很多開源可用的java表達(dá)式求值引擎,為什么還需要Avaitor呢?
Aviator的設(shè)計(jì)目標(biāo)是輕量級和高性能,相比于Groovy、JRuby的笨重,Aviator非常小,加上依賴包也才450K,不算依賴包的話只有70K;當(dāng)然,Aviator的語法是受限的,它不是一門完整的語言,而只是語言的一小部分集合。
其次,Aviator的實(shí)現(xiàn)思路與其他輕量級的求值器很不相同,其他求值器一般都是通過解釋的方式運(yùn)行,而Aviator則是直接將表達(dá)式編譯成Java字節(jié)碼,交給JVM去執(zhí)行。簡單來說,Aviator的定位是介于Groovy這樣的重量級腳本語言和IKExpression這樣的輕量級表達(dá)式引擎之間。

Aviator的特性

  • 支持大部分運(yùn)算操作符,包括算術(shù)操作符、關(guān)系運(yùn)算符、邏輯操作符、正則匹配操作符(=~)、三元表達(dá)式?:,并且支持操作符的優(yōu)先級和括號強(qiáng)制優(yōu)先級,具體請看后面的操作符列表。
  • 支持函數(shù)調(diào)用和自定義函數(shù)
  • 支持正則表達(dá)式匹配,類似Ruby、Perl的匹配語法,并且支持類Ruby的$digit指向匹配分組。
  • 自動類型轉(zhuǎn)換,當(dāng)執(zhí)行操作的時(shí)候,會自動判斷操作數(shù)類型并做相應(yīng)轉(zhuǎn)換,無法轉(zhuǎn)換即拋異常。
  • 支持傳入變量,支持類似a.b.c的嵌套變量訪問。
  • 性能優(yōu)秀

Aviator的限制

  • 沒有if else、do while等語句,沒有賦值語句,沒有位運(yùn)算符
  • 僅支持邏輯表達(dá)式、算術(shù)表達(dá)式、三元表達(dá)式和正則匹配

Aviator用法

最新jar包

    <dependency>
        <groupId>com.googlecode.aviator</groupId>
        <artifactId>aviator</artifactId>
        <version>2.3.4</version>
    </dependency>

算術(shù)表達(dá)式

Long result = (Long)AviatorEvaluator.execute("1+2+3");
System.out.println(result);//6

note:Aviator的數(shù)值類型僅支持Long和Double,任何整數(shù)都將轉(zhuǎn)換成Long,任何浮點(diǎn)數(shù)都將轉(zhuǎn)換為Double,包括用戶傳入的變量數(shù)值。

邏輯表達(dá)式

Boolean result2 = (Boolean)AviatorEvaluator.execute("3>1 && 2!=4 || true");
System.out.println(result2);//true

變量和字符串相加

Map env = newHashMap();
env.put("yourname","aviator");
String result3 = (String)AviatorEvaluator.execute(" 'hello ' + yourname ", env);
System.out.println(result3);

上面的例子演示了怎么向表達(dá)式傳入變量值,表達(dá)式中的yourname是一個(gè)變量,默認(rèn)為null,通過傳入Map的變量綁定環(huán)境,將yourname設(shè)置為你輸入的名稱。env的key是變量名,value是變量的值。
Aviator 2.2開始新增加一個(gè)exec方法,可以更方便地傳入變量并執(zhí)行,而不需要構(gòu)造env這個(gè)map了:

String result4= (String) AviatorEvaluator.exec(" 'hello ' + yourname ","aviator2");
System.out.println(result4);

三元表達(dá)式

String result5=(String)AviatorEvaluator.execute("3>0? 'yes':'no'");
System.out.println(result5);

函數(shù)調(diào)用

AviatorEvaluator.execute("string.length('hello')");    //求字符串長度
AviatorEvaluator.execute("string.contains('hello','h')");  //判斷字符串是否包含字符串AviatorEvaluator.execute("string.startsWith('hello','h')");  //是否以子串開頭AviatorEvaluator.execute("string.endsWith('hello','llo')");是否以子串結(jié)尾
AviatorEvaluator.execute("math.pow(-3,2)");   //求n次方
AviatorEvaluator.execute("math.sqrt(14.0)");   //開 平方根
AviatorEvaluator.execute("math.sin(20)");    //正弦函數(shù)

參考文章

Aviator官方文檔
Aviator——讓表達(dá)式飛起來
表達(dá)式引擎aviator

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,534評論 19 139
  • 第5章 引用類型(返回首頁) 本章內(nèi)容 使用對象 創(chuàng)建并操作數(shù)組 理解基本的JavaScript類型 使用基本類型...
    大學(xué)一百閱讀 3,674評論 0 4
  • 第一部分Common Lisp介紹第1章 介紹一下Lisp你在學(xué)的時(shí)候覺得已經(jīng)明白了,寫的時(shí)候更加確信了解了,教別...
    geoeee閱讀 3,218評論 5 8
  • 應(yīng)用方式 1、內(nèi)聯(lián)式 2、嵌入式 3、外部鏈接式 4、導(dǎo)入式 @import 選擇符類型 1、類型選擇符 ...
    遙星夢閱讀 293評論 0 0
  • 我們都長大了 離開年少輕狂 離開溫暖港灣 我們都長大了 眼中滿含堅(jiān)定 心中充滿期待 我們褪去稚嫩 我們收獲酸甜...
    三杯茶王一閱讀 415評論 4 2

友情鏈接更多精彩內(nèi)容