规则引擎架构-基于aviator

aviator使用场景

github地址:aviator

使用场景:

  • 规则判断及规则引擎
  • 公式计算
  • 动态脚本控制
  • 集合数据 ELT 等 ……

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的逻辑

猜你喜欢

转载自blog.csdn.net/qq_26437925/article/details/130937869