百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术教程 > 正文

学会动态脚本语言AviatorScript,处理规则配置不再愁

suiw9 2025-03-19 16:32 4 浏览 0 评论

AviatorScript

AviatorScript 是一门依赖于JVM虚拟机的高性能和轻量级的动态脚本语言。Aviator从原来的表达式引擎到现在脚本语言,支持了更多的特性特性。

原理和特点

Aviator 的基本过程是将表达式直接翻译成对应的 java 字节码执行,除了依赖 commons-beanutils 这个库之外(用于做反射)不依赖任何第三方库,因此整体非常轻量级,整个 jar 包大小哪怕发展到现在 5.0 这个大版本,也才 430K。同时, Aviator 内置的函数库非常“节制”,除了必须的字符串处理、数学函数和集合处理之外,类似文件 IO、网络等等你都是没法使用的,这样能保证运行期的安全,如果你需要这些高阶能力,可以通过开放的自定义函数来接入。

编译过程

Hello World示例

hello world

1、创建maven项目,添加以下依赖,目前最新版本是5.3.3。

  
      com.googlecode.aviator
      aviator
      5.3.3
  

获取一个AviatorEvaluator实例,默认是编译执行,如果指定EvalMode.INTERPRETER,怎解析执行,这种模式生产指令并解释执行。解释执行的效率远远低于编译执行,编译执行可以使用getInstance()方法或者指定EvalMode=ASM。

Expression exp = AviatorEvaluator.newInstance(EvalMode.ASM).compile("(a+b)>c");
Map env = new HashMap<>();
env.put("a", 12);
env.put("b", 5);
env.put("c", 20);
Boolean execute = (Boolean) exp.execute(env);
System.out.println(execute);
//执行结果 flase

数据类型及运算

Aviator支持的数据类型有:整数(long),浮点数(Double),大整数(bigInt),高精度(BigDecimal),字符串,布尔值(Boolean)。单一类型参与的运算,结果仍然为该类型,多种类型参与的运算,按照下列顺序: long -> bigint -> decimal -> double 自动提升。通过一个例子演示这些数据类型及运算。

## av/exp.av
## 数据类型和运算
let l = 123456789;                           ## long
let d = 12.0123;                               ## double
let bi = 10223372036854774807N; ##bigint以N结尾
let bd = 112.112M;                          ##BigDecimal以M结尾
let str = "hello zhangsan";                ##只要以单引号或者双引号括起来的连续字符就是一个完整的字符串对象

println(l+l); ##结果为long,如果超过long限制自动转成bigInt
println(d*d);
println(bi*bi);
println(l+d);
println(bi*d);
println(bd/l);
let newStr = str+"!"; ## 拼接字符串使用+
println(newStr);
println(string.length(newStr)); ## 计算字符串的长度
println("3<4 = "+(3<4))  ##boolean
let score = 99;
let result = (score>85)?"优秀":score; ## 三元运算符可以返回不同类型的值
println(result)

对于运算处理基本的加减乘除,还有幂运算、比较运算、逻辑运算、三元运算和正则匹配和位运算等

  • 幂运算使用math.pow(a, b)或者a**b
  • 比较运算:>,>=,<,<=,!=,==
  • 逻辑运算:逻辑与&&、逻辑或||、逻辑否! ,对于逻辑与和逻辑非可使用别名and和or。
  • 位运算:位与&,或|,异或^,左移<<,右移>>,无符号右移>>>
  • 三元运算:a?b:c当a的值为true时表达式的值为b,否则为c

变量声明和作用域:

声明一个变量可以使用let关键字,let声明的变量是全局变量,在整个脚本有效。如果使用let 在子代码块中定义一个变量,并且其父作用域有同名的变量,将“掩盖”父作用域的变量,如果不使用 let ,读写的将仍然是父作用域的变量。

声明变量时要对变量赋值,如果不想赋值请使用nil,nil相当于Java中的null,表示没有赋值,可以对nil做比较运算,nil以外的都大于nil,但是不能对nil做其他的运算。

创建一个av文件,声明一个变量a赋值为nil,返回一个三元运算符计算结果,最后脚本应该返回c的值。注意,Aviator默认返回最后表达式的结果,但是最后有分号的情况下,整个脚本返回nil。下面脚本最后使用了return语句返回结果,如果没有return,则整个脚本返回nil,除非把最后的分案去掉。

## av/variable.av
let a = nil;
return a > 1? b : c;

测试上面的脚本结果,使用exp.getVariableNames()获取所有的变量名字,发现只用b和c。最后通过newEnv生成map对象并存储key和value值。

Expression exp = AviatorEvaluator.getInstance().compileScript("av/variable.av");
System.out.println(exp.getVariableNames());
//打印 [b, c]
System.out.println(exp.execute(exp.newEnv("b", 20, "c", 30)));
//打印 30

在 AviatorScript 中,每个语句都有一个值,可以使用if和循环对一个变量赋值,请看下面的例子。

let ifResult = if(a == 10){
    a+100
};
println(ifResult);
let forResult = for x in range(0, 10) {
   x
};
println(forResult);
let whileResult = while true {
                  sum = sum + sum;
                  if sum > 1000 {
                    return sum;
                  }
                };
println(whileResult);

最后简单介绍下循环,循环可以使用for和while,for的语法为for .. in 后面是数组,list或者map等集合,wihile循环为while关键字和条件的结合,例子如下:

for i in range(0,10){
    println(i);
}
let i = 1;
while i < 8{
    i = i+1;
    println(i)
}

在循环中可以使用break跳出循环,或者使用continue跳过本次循环继续执行,类似Java语言。

函数,数组、集合和 Sequence

函数

通过 fn 语法来定义一个命名函数或者使用lamdba定义一个匿名的函数。请看下面的例子,特殊情况已在代码中说明。

##fn的语法,&args表示不定长参数
fn concat(a, b,  &args){
  let ret = a + b;
  let r = for arg in args{
      ret = ret + arg;
  }
 	return ret;  
}
 
 ##匿名函数 lambda (参数1,参数2...) -> 参数体表达式 end
 let three = (lambda (x,y) -> x + y end)(1, 2);
 ## 对于匿名的函数,可以赋值给一个变量,
 let add = lambda (x,y) -> x + y end;
 three = add(1,2);
 
 ## 从 5.2.4 开始,匿名函数的定义也可以用 fn 语法
 let add =fn (x,y) {x+y};

在AviatorScript 中将数组和集合都抽象成一个序列集合 Sequence,在此之上可以用同一套高阶函数方便地操作任意的数组或者集合。

1、可以使用tuple创建固定大小的数组

2、使用seq.array方法创建数组并填充,或者使用array_of创建空数组

3、创建list使用seq.list方法

4、创建map使用seq.map(k1, v1, k2, v2 ...)方法

5、创建set使用seq.set,set是不重复的集合

let t = tuple(1, 2, "hello", 3.14);
let a1 = seq.array(int, 1, 2, 3, 4);
let a2 = seq.array_of(int, 3);
let a3 = seq.array_of(long, 3, 2);
let list = seq.list(1, 2, 3);
## 使用add添加元素
seq.add(list, 4);
let map = seq.map("a", 1, "b", 2, "c", 3);
## 使用remove删除元素
seq.remove(map, 0);
let s = seq.set(1, 2, 3, "hello","hello");
## 使用get获取元素
let mg = seq.get(map, 0);

Sequence 是 AviatorScript 对“集合”的抽象。Sequence接口继承了Iterable接口,代表可遍历的对象。接口中的两个方法:hintSize()用于返回集合的元素数量,newCollector() 用于收集 sequence 里的元素经过某种“变化”后的结果。

public interface Sequence extends Iterable {
    Collector newCollector(int var1);

    int hintSize();
}

创建对象和引用Java类

使用new创建对象,对于java.lang包的类可以直接使用,对于之外的需要添加完成的包名和类名,从 版本5.2 开始,aviatorscript 支持 use 语句导入类。

let d = new java.util.Date();
let s = new String("zhangsan");
use java.util.Date; ##导入单个类
let d = new Date();
use java.util.*;##导入util下的所有类
use java.util.{Date,ArrayList};## 导入指定的类 use 包名.{类1, 类2...} 

使用场景

总结

1、Aviator一开始的定位为表达式语言,首先能用作表达式的运算

2、在业务复杂规则配置的时候可以动态生成脚本并执行规则判断

3、使用在规则引擎中

相关推荐

昆仑通态初级入门(昆仑通态选型)

1时间的显示方法1:1新建窗口2点击工具箱中插入元件图标,选择时钟,时钟1,然后确定...

案例分析:企业消息通知管理平台设计

企业消息需要通知及时又不过度打扰,如果经由专门的消息管理平台送达,这个平台在设计上应该注意什么问题?在企业日常运作中,一般有三种由企业发起的通知信息:重要且正式的新闻通知,比如领导任命通知、新颁布的行...

Windows CMD 命令大全:简单粗暴收藏!

WindowsCMD是Windows系统内置的命令行工具,用于执行各种命令和管理任务。以下是CMD的基础知识和常用命令。...

软网推荐:超强的免费文件重命名利器

Windows10的文件资源管理器虽然也具有批量文件重命名的功能,但由于无法满足人们对批量文件命名的多样化需求,因此往往还需要借助于第三方软件来解决问题。在众多的文件批量重命名工具中,Rename...

CAD最强插件,掌握此插件十分之一的功能,你就是绘图大师

推荐退出360杀毒软件再下载,插件会被误杀,导致不能安装。"源泉建筑与装饰设计CAD工具箱(简称:...

相见恨晚:windows十款必装的逆天神器

本文首发于什么值得买平台请关注本账号获取更多好文,作者:纵笔浮生【写在前面】今天给大家带来了十款轻量级的软件,虽然小,有的或许简陋,但是真的能解决很多痛点,真正碰到了就是一个解决问题的好助手。可能有点...

零基础Python自学教程9:Python中运算符的优先级和条件表达式

欢迎你来到站长学堂,学习站长在线出品的在线课程《零基础Python完全自学教程》今日分享的是第9课《Python中运算符的优先级和条件表达式》。本节课主要内容有:Python中运算符的优先级、Pyth...

想要字体图标设计师却给了SVG?没关系,自己转

本文为Varlet组件库源码主题阅读系列第三篇,读完本篇,你可以了解到如何将svg图标转换成字体图标文件,以及如何设计一个简洁的Vue图标组件。...

聊聊字符集编码与数据压缩(字符集和编码的区别)

1.字符集与编码字符集:表示多个字符的集合,如符号,序号、数字,其它等等。字符编码:把字符编码为指定集合中的某一对象,变成一种特定的字节或字节序列,在计算机中便于存储,传输。通常字符集都采用对应的编码...

对象存储方案大比拼--OSS、MinIO、Ceph、Apache Ozone 与 OpenIO

在当今数据驱动的时代,选择合适的对象存储方案对于企业和开发者来说至关重要。本文将对本地存储、阿里云OSS、MinIO、Ceph、ApacheOzone和OpenIO这几种常见的对象存储方案进...

技术篇:如何构建安全的Kafka集群(kafka集群创建topic)

Kafka是由LinkedIn设计的一个高吞吐量、分布式、基于发布订阅模式的消息系统,使用Scala编写,它以可水平扩展、可靠性、异步通信和高吞吐率等特性而被广泛使用。目前越来越多的开源分布式处理系统...

为何Kafka在2.8版本开始会“抛弃”Zookeeper?

一、Kafka简介在讲解为何Kafka在2.8版本开始会“抛弃”Zookeeper?之前,先来介绍一下kafka和Zookeeper在kafka中的作用?...

博主好贴心,为已有的 ambari 集群修改主机名

回复“资源”领取独家整理的学习资料!...

0727-6.3.0-在CDH上运行你的第一个Flink例子

文档编写目的ClouderaDataFlow(CDF)作为Cloudera一个独立的产品单元,围绕着实时数据采集,实时数据处理和实时数据分析有多个不同的功能模块,如下图所示:...

详细介绍一下Spring Boot中如何使用Hive?

Hive是一个基于Hadoop实现的数据仓库工具,提供了强大的SQL操作支持,可以用来实现大数据分析和处理。通过Hive与SpringBoot的集成可以更快更高效的实现数据的查询与处理,下面我们就来...

取消回复欢迎 发表评论: