原文:https://www.yuque.com/boyan-avfmj/aviatorscript
AviatorScript 文档
起源
Aviator 起源于 2010 年左右,当时我还在淘宝中间件,读了龙书,了解了 ASM ,开始读 clojure 编译器的源码。刚好同时在做 Notify 这个内部消息中间件的一个重要版本实现,其中有一个需求是实现 AMQP 规范里的 header 订阅,允许用户指定一个布尔表达式来决定是否订阅某种类型的消息,需要对布尔表达式字符串进行求值。当时正处于造轮子的兴奋期,因此就写了第一个版本出来,第一个版本花了一两天的功夫,整个代码结构其实到现在也没有特别大的改变,还是那么乱 :)
表达式引擎当时国内开源的已经有 IKExpression,可惜是纯解释执行的,效率很一般,Groovy 刚开始流行,性能不错,但是整体很重量级,更重要的原因是我们希望控制用户能使用的语法和函数,需要一个定制的“子集”,因此 Aviator 就诞生了。
后来这个库用到了很多公司的很多地方,并且不少场景都是出乎我的意料之外的,常见的公式计算不提,也有用在数据处理转换、数据核对以及工作流逻辑判定、鉴权校验等等。这也是我继续发展它的动力。
原理和特点
Aviator 的基本过程是将表达式直接翻译成对应的 java 字节码执行,整个过程最多扫两趟(开启执行优先模式,如果是编译优先模式下就一趟),这样就保证了它的性能超越绝大部分解释性的表达式引擎,测试也证明如此;其次,除了依赖 commons-
beanutils
这个库之外(用于做反射)不依赖任何第三方库,因此整体非常轻量级,整个 jar 包大小哪怕发展到现在 5.0 这个大版本,也才 430K。同时, Aviator 内置的函数库非常“节制”,除了必须的字符串处理、数学函数和集合处理之外,类似文件 IO、网络等等你都是没法使用的,这样能保证运行期的安全,如果你需要这些高阶能力,可以通过开放的自定义函数来接入。因此总结它的特点是:
- 高性能
- 轻量级
- 一些比较有特色的特点:
- 支持运算符重载
- 原生支持大整数和 BigDecimal 类型及运算,并且通过运算符重载和一般数字类型保持一致的运算方式。
- 原生支持正则表达式类型及匹配运算符
=~
- 类 clojure 的 seq 库及 lambda 支持,可以灵活地处理各种集合
- 开放能力:包括自定义函数接入以及各种定制选项
AviatorScript:5.0
任何使用 5.x 版本的朋友,请升级到 5.2.6 及以上版本。
Aviator 原来的定位一直只是一个表达式引擎,不支持 if/else 条件语句(仅有三元运算符支持 ?:
),没有内置的 for/while 循环支持(虽然你可以用 seq 库类似函数式的方式来处理集合),也没有赋值(后来在 4.0 引入),没有作用域的概念(也在 4.0 引入 lambda 函数后部分实现)等等一般语言常见的能力。不过在 5.0 这个大版本(也就是本指南介绍的主要版本)将支持上述所有的能力,变成一门通用的脚本语言 AviatorScript:
- 词法作用域
{...}
,和let
定义作用域内的变量 return
语句,用于从函数或者 script 中返回(值)。if/elsif/else
条件语句for/while
循环语句,以及break
/continue
支持fn
语法用于定义命名函数, 4.0 已经引入了lambda -> ... end
语法专门用于匿名函数定义## 单行注释
支持- 和 Java Scripting API 更好的集成
- 字符串插值
- 异常处理
try...catch...finally
语句等等。
没有改变的是:
- 继续保持轻量化。
- 还是 two pass 编译,最终生成 JVM 字节码,保证性能比一般解释型脚本快。
- 内置函数继续“节制”,但是现在也有很灵活的方式来调用任何 Java 类的方法。
- 几乎向前兼容,不兼容的地方很少,我们将在发布版本里说明。
为什么还要有 aviator ?
这是有人向我提出来的问题,既然 groovy/kotlin/jruby 都发展的这么好,还有没有必要发展 AviatorScript?我直接用他们不也是挺好的。
我的答案是没错,优先使用社区广泛使用的语言,有一个比较好的社区支持,这都是很好、很正确的考量。那么为什么还想要发展和去使用 AviatorScript? 我能想到的理由如下:
- 我可以,并且我将继续维护它
- 你不想使用一个全功能的、相对重量级的语言,你只是做一些布尔表达式判定、数据集合处理等等,你不想引入一堆依赖,并且期待有一定的性能保证。AviatorScript 提供了大量的定制选项,甚至各种语法特性都是可以开关的。
- 你的表达式或者 script 是用户输入的,你无法保证他们的安全性,你希望控制用户能使用的 API,提供一个相对安全的运行沙箱
- 你原来的项目在使用 aviator,有一堆遗留的表达式要维护,原来没有很好的条件语句、循环语句等能力支持,让你的使用受限了。
- 你就是喜欢 AviatorScript 的语法
- 你就是想用它
老版本如何升级到 5.0 大版本?
请阅读文档《如何升级到 5.0 大版本(老用户必读)》。
感谢所有用户的支持,有问题可以随时到 github 反馈