目录

    • aviator使用场景
    • ASM 字节码操控框架
    • aviator 表达式例子
      • debug
      • 表达式类生成过程
        • `b-c+a`生成的class文件

aviator使用场景

github地址:aviator

Aviator的特性

  • 支持大部分运算操作符,包括算术操作符、关系运算符、逻辑操作符、正则匹配操作符(=~)、三元表达式?: ,并且支持操作符的优先级和括号强制优先级,具体请看后面的操作符列表。
  • 支持函数调用和自定义函数
  • 支持正则表达式匹配,类似Ruby、Perl的匹配语法,并且支持类Ruby的$digit指向匹配分组。
  • 自动类型转换,当执行操作的时候,会自动判断操作数类型并做相应转换,无法转换即抛异常。
  • 支持传入变量,支持类似a.b.c的嵌套变量访问。
  • 性能优秀

Aviator的限制:

  • 没有if else、do while等语句,没有赋值语句,仅支持逻辑表达式、算术表达式、三元表达式和正则匹配。
  • 没有位运算符

ASM 字节码操控框架

asm实现:直接修改或生成.class

例子代码

package com.googlecode.aviator;import com.googlecode.aviator.asm.ClassWriter;import com.googlecode.aviator.asm.MethodVisitor;import com.googlecode.aviator.asm.Opcodes;/** * @author dingqi on 2023/5/29 * @since 1.0.0 */public class TestAsm extends ClassLoader{/** * 生成一个Class类 * public class User { * * public static void main(String[] args) { * System.out.println("Hello World"); * } * * public int add(int a, int b){ * return a + b; * } * } */public static byte[] generateClazz() {ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);cw.visit(Opcodes.V1_7,Opcodes.ACC_PUBLIC,"com/googlecode/aviator/User",null,"java/lang/Object",null);MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC,"","()V",null,null);// 开始访问方法codemv.visitCode();// 局部变量进栈mv.visitVarInsn(Opcodes.ALOAD, 0);// 执行特殊实例方法(构造方法)mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "", "()V");// 方法返回mv.visitInsn(Opcodes.RETURN);// 最大栈大小值、最大方法本地参数值mv.visitMaxs(1, 1);// 方法结束mv.visitEnd();mv = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC,"main","(Ljava/lang/String;)V",null,null);// 开始访问方法codemv.visitCode();// 访问static类字段out,参数类型Ljava/io/PrintStream;mv.visitFieldInsn(Opcodes.GETSTATIC,"java/lang/System","out","Ljava/io/PrintStream;");// 常量加载进栈mv.visitLdcInsn("Hello World");// 调用对象的实例方法println,方法参数String数组(Ljava/lang/String;)Vmv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,"java/io/PrintStream","println","(Ljava/lang/String;)V");// 方法返回mv.visitInsn(Opcodes.RETURN);// 最大栈大小值、最大方法内本地参数值mv.visitMaxs(2, 1);// 方法结束mv.visitEnd();// 再添加方法mv = cw.visitMethod(Opcodes.ACC_PUBLIC,"add","(II)I",null,null);// 入参mv.visitVarInsn(Opcodes.ILOAD,1);mv.visitVarInsn(Opcodes.ILOAD,2);mv.visitInsn(Opcodes.IADD); //2个int类型相加//返回int 类型mv.visitInsn(Opcodes.IRETURN);// 设置操作数栈的深度和局部变量的大小:2个数计算,加上this 总共3个变量mv.visitMaxs(2, 3);mv.visitEnd();cw.visitEnd();return cw.toByteArray();}public static void main(String[] args) throws Exception {TestAsm testAsm = new TestAsm();byte[] code = TestAsm.generateClazz();String className = "com.googlecode.aviator.User";Class<" />> clazz = testAsm.defineClass(className, code, 0, code.length);clazz.getMethods()[0].invoke(null, new Object[]{null});Object o = clazz.newInstance();Integer ans = (Integer)clazz.getMethods()[1].invoke(o, 1, 2);System.out.println("add ans:" + ans);ans = (Integer)clazz.getMethods()[1].invoke(o, 1, 3);System.out.println("add ans:" + ans);}}/** 输出 Hello World add ans:3 add ans:4 */

aviator 表达式例子

public class AviatorEvaluatorInstanceUnitTest {protected AviatorEvaluatorInstance instance;@Beforepublic void setup() {this.instance = AviatorEvaluator.newInstance();}@Testpublic void testExec() {String exp1 = "b-c+a";assertEquals(8, this.instance.exec(exp1, 6, 2, 4));}}

debug


新生成了一个类Script_1685399425946_58

执行execute0方法,参数:com.googlecode.aviator.utils.Env

然后执行成功,得到结果

debug可以看到生成的类确实有方法:public final java.lang.Object Script_1685400413476_58.execute0(com.googlecode.aviator.utils.Env)

表达式类生成过程

依据

String exp1 = "b-c+a";assertEquals(8, this.instance.exec(exp1, 6, 2, 4));


解析完变量后的asm生成逻辑:

 private void callASM(final Map<String, VariableMeta/* metadata */> variables,final Map<String, Integer/* counter */> methods, final Set<Token<" />>> constants) {this.codeGen.initConstants(constants);this.codeGen.initVariables(variables);this.codeGen.initMethods(methods);this.codeGen.setLambdaBootstraps(this.lambdaBootstraps);this.codeGen.start();

生成execute0方法

 @Overridepublic void start() {makeConstructor();startVisitMethodCode();}
private void startVisitMethodCode() {this.mv = this.classWriter.visitMethod(ACC_PUBLIC + +ACC_FINAL, "execute0","(Lcom/googlecode/aviator/utils/Env;)Ljava/lang/Object;","(Lcom/googlecode/aviator/utils/Env;)Ljava/lang/Object;", null);this.mv.visitCode();}

可以debug写到class文件查看, className文件名Script_1685767852489_58

b-c+a生成的class文件
public class Script_1685767852489_58 extends ClassExpression {private final AviatorJavaType f0;private final AviatorJavaType f1;private final AviatorJavaType f2;public Script_1685767852489_58(AviatorEvaluatorInstance var1, List var2, SymbolTable var3) {super(var1, var2, var3);this.f2 = new AviatorJavaType("a", var3);this.f0 = new AviatorJavaType("b", var3);this.f1 = new AviatorJavaType("c", var3);}public final Object execute0(Env var1) {return this.f0.sub(this.f1, var1).add(this.f2, var1).getValue(var1);}}

参数通过构造函数设置好,然后一个exceute0方法内部就是执行b-c+a的逻辑