规则引擎架构-基于aviator

news2024/11/17 19:44:05

目录

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/604680.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Dubbo】Dubbo架构的演进过程分析

&#x1f4eb;作者简介&#xff1a;小明java问道之路&#xff0c;2022年度博客之星全国TOP3&#xff0c;专注于后端、中间件、计算机底层、架构设计演进与稳定性建设优化&#xff0c;文章内容兼具广度、深度、大厂技术方案&#xff0c;对待技术喜欢推理加验证&#xff0c;就职于…

Go并发编程 Goroutine、Channel、Select、Mutex锁、sync、Atomic等

本文所有实例代码运行go版本&#xff1a;go version go1.18.10 windows/amd64 1 并发编程介绍 1.1 串行、并发、并行 串行&#xff1a;所有任务一件一件做&#xff0c;按照事先的顺序依次执行&#xff0c;没有被执行到的任务只能等待。最终执行完的时间等于各个子任务之和。…

效率神器!神级ChatGPT浏览器插件分享

大家好&#xff0c;我是卷了又没卷&#xff0c;薛定谔的卷的AI算法工程师「陈城南」~ 担任某大厂的算法工程师&#xff0c;带来最新的前沿AI知识和工具&#xff0c;欢迎大家交流~&#xff0c;后续我还会分享更多 AI 有趣工具和实用玩法&#xff0c;包括AI相关技术、ChatGPT、AI…

初识SpringBoot -- SpringBoot入门保姆级教程(一)

文章目录 前言一、初识SpringBoot1.SpringBoot简介2.用编译器IDEA创建SpringBoot项目3.在官网创建SpringBoot项目4.SpringBoot项目快速启动&#xff08;前后端分离基本能力&#xff09;5.了解SpringBoot起步依赖和启动类 总结 前言 为了巩固所学的知识&#xff0c;作者尝试着开…

RocketMQ消息消费

RocketMQ消息消费示例代码&#xff1a; public static void main(String[] args) throws InterruptedException, MQClientException {DefaultMQPushConsumer consumer new DefaultMQPushConsumer("please_rename_unique_group_name_4");consumer.setNamesrvAddr(&qu…

C++ 学习 ::【基础篇:15】:C++ 类的基本成员函数:析构顺序问题(全局/静态/局部量) 及 类类型(自定义类型)与析构函数

本系列 C 相关文章 仅为笔者学习笔记记录&#xff0c;用自己的理解记录学习&#xff01;C 学习系列将分为三个阶段&#xff1a;基础篇、STL 篇、高阶数据结构与算法篇&#xff0c;相关重点内容如下&#xff1a; 基础篇&#xff1a;类与对象&#xff08;涉及C的三大特性等&#…

Nginx配置块location及rewrite详解(遗憾)

文章目录 一、location配置块详解1.location 大致分为三类2.location 常用的匹配规则3.location 匹配的优先级4.location 匹配流程5.location 的实际使用&#xff08;1&#xff09;直接匹配网站根目录首页&#xff08;2&#xff09;处理静态文件请求&#xff08;3&#xff09;通…

函数式接口相关知识点

这里写目录标题 函数式接口简介以及注意点函数式接口作为方法的参数函数式接口作为方法参数常用的函数式接口Supplier简介具体代码操作 Consumer简介具体代码演示演示1演示2 Predicate接口简介以及接口中的方法text和negate方法and和or方法Function方法简介具体操作1具体操作2 …

SQL语句之DDL语言

说明&#xff1a;DDL&#xff08;Data Definition Language&#xff0c;数据定义语言&#xff09;&#xff0c;用来定义数据库对象(数据库、表)&#xff0c;包括了数据库和表的创建、查询、使用和删除操作。 一、数据库操作 新安装的数据库&#xff0c;默认有以下四个数据库&…

计算机网络-数据链路层

概念 结点&#xff1a;主机、路由器 链路&#xff1a;结点间物理通道 数据链路&#xff1a;结点间逻辑通道&#xff0c;控制数据传输协议的硬件和软件加到链路上构成数据链路 帧&#xff1a;链路层的协议数据单元&#xff0c;封装网络层数据报 数据链路层负责通过一条链路从一…

银行转账问题(死锁)

本文主要讲述死锁的一个经典案例—银行转账问题&#xff0c;并对该问题进行定位、修复。 1. 问题说明 当账户A对账户B进行转账时&#xff0c; 首先需要获取到两把锁&#xff1a;账户A和账户B的锁。获取两把锁成功&#xff0c;且余额大于0&#xff0c;则扣除转出人的余额&…

我记不住的那些C语言的struct知识

背景&#xff1a; 最近在重学C语言&#xff0c;目的是为了能看懂操作系统的底层代码&#xff0c;也为后续使用C语言开发一个类似redis数据库的中间件做准备&#xff0c;于是又重新踏上了学习C语言的道路&#xff0c;早在上学期间就学习过C语言&#xff0c;但是很久都不用了&…

ssm学习-spring01

Spring_day01 今日目标 掌握Spring相关概念完成IOC/DI的入门案例编写掌握IOC的相关配置与使用掌握DI的相关配置与使用1,课程介绍 对于一门新技术,我们需要从为什么要学、学什么以及怎么学这三个方向入手来学习。那对于Spring来说: 1.1 为什么要学? 从使用和占有率看 Spri…

使用 ChatGPT API 构建系统(一):分类

今天我学习了DeepLearning.AI的 Building Systems with the ChatGPT API 的在线课程&#xff0c;我想和大家一起分享一下该门课程的一些主要内容。 下面是我们通过Openai API来访问ChatGPT模型的主要代码&#xff1a; import openai#您的openai的api key openai.api_key YOUR…

chatgpt赋能python:Python删除节点:从入门到实践

Python删除节点&#xff1a;从入门到实践 在任何编程语言中&#xff0c;删除节点都是一个极为常见的操作。在Python中&#xff0c;它同样非常重要&#xff0c;因为我们通常会使用Python处理各种数据结构&#xff0c;诸如树、链表等等。但是&#xff0c;删除节点并不总是一件容…

C++类和对象 -- 知识点补充

补充 const成员函数static成员友元内部类匿名对象拷贝对象时的一些编译器优化 const成员函数 将const修饰的成员函数称为const成员函数&#xff0c;const修饰类成员函数&#xff0c;实际是修饰该成员函数隐含的this指针&#xff0c;表明在该成员函数中不能对类的成员进行修改。…

javaWeb ssh自习室管理系统myeclipse开发mysql数据库MVC模式java编程计算机网页设计

一、源码特点 java ssh自习室管理系统是一套完善的web设计系统&#xff08;系统采用ssh框架进行设计开发&#xff09;&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S 模式开发。开发环境为TOMCAT7.0,…

预报名通道已开启,2023第11届国际生物发酵展,8月4-6日上海见!

新机遇、新挑战、新发展 同期展会&#xff1a;酵素产品与益生产品展 制药机械与包装技术展 生化仪器及实验室设备展 合成生物技术与生物制造展 展会时间&#xff1a; 2023年8月4日 9:00-17:00 2023年8月5日 9:00-17:00 2023年8月6日 9:00-15:00 展会地点&#xff1a…

【数据结构】栈和队列选择题和面试编程题

目录 一、选择题 二、栈和队列的面试题 1、括号匹配问题 1.1 题目说明 1.2 题目解析 2、用队列实现栈 2.1 题目说明 2.2 题目解析 3、用栈实现队列 3.1 题目说明 3.2 题目解析 一、选择题 1、若进栈序列为 1,2,3,4 &#xff0c;进栈过程中可以出栈&#xff0c;则下列不可能的…

软考A计划-电子商务设计师-信息安全知识

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例 &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分享&am…