规则引擎架构-基于aviator

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,
                "<init>",
                "()V",
                null,
                null
        );
        // 开始访问方法code
        mv.visitCode();
        // 局部变量进栈
        mv.visitVarInsn(Opcodes.ALOAD, 0);
        // 执行特殊实例方法(构造方法)
        mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()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
        );
        // 开始访问方法code
        mv.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;)V
        mv.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;

  @Before
  public void setup() {
    this.instance = AviatorEvaluator.newInstance();
  }

  @Test
  public 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方法

 @Override
  public 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的逻辑

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值