借老系统重构机会我写了个groovy规则引擎

devtools/2024/9/23 10:24:30/

公司老系统的重构计划早就有了,为了对Java硬编码的各种校验规则进行重构,特地参考了相关技术,最终选择了groovy进行了系统的学习,并编写了一个即插即用的轻量级规则引擎

文章目录

    • 项目背景
    • 技术选型
    • groovy的性能
    • 统一Java运行环境
    • dsl风格的规则声明
    • 弱类型的便利
    • 校验规则的维护
    • 基于事实推断的规则引擎实现

项目背景

笔者上班负责的是一个很老的某业务平台的申报系统。并发量随不高,但是申报分了很多的阶段,且每个阶段的申报项比较多,表单的字段也很多,校验规则也比较杂。项目前期有多个团队先后负责,代码风格不同,且业务规则的校验实现都是堆砌代码的方式,导致后期的代码维护比较麻烦。一个类文件通常是5千行代码以上,一个校验方法也至少几百行。

因为业务操作主要是数据的保存和申报,而校验的代码占到很大的比例,为此笔者的重构,很自然就想到把各种杂七杂八的校验代码给抽取出来,以规则脚本的形式进行更好的维护。

技术选型

抽取校验规则的技术选型,考虑了基于rete算法的drools、基于mveleasyRule以及jvm体系的groovy。因为只是把系统中的校验规则抽取出来,做成脚本的形式维护,传统的规则引擎也基本用不上,因为它们更多的使用场景是基于多实体的事实对象的分析、推断,且比较重量级,且有一定的学习成本。而groovy本身就是一门动态的脚本语言,很轻量级,可以在java环境无缝衔接的调用,语法非常的简洁易学,它的dsl特性还能编写出可读性更高的脚本声明形式。

groovy_13">groovy的性能

groovy非常的轻量级,编译速度很快,新版本对编译的内容做了缓存,而且gc方面也做了优化。笔者在这方面做了一些实验:通过spring boot的定时任务每隔一秒钟用30个线程同时跑groovy规则脚本,并对应用的jvm参数-XX:MetaspaceSize-XX:MaxMetaspaceSize都做了限制。用groovy老版本和新版本做了下对比,发现老版本执行很快就oom了:

在这里插入图片描述

而新版本稳定发挥,执行的性能用visualVM监控了下:

在这里插入图片描述

笔者还测试了下规则执行的耗时,第一次访问时需要耗时几百毫秒,后续就很快了,说明重复执行一个规则脚本,会缓存一些编译的类,提高性能:

在这里插入图片描述

统一Java运行环境

在植入groovy脚本代码到当前的java系统时,可以设置加载groovy的类加载器为当前java系统的类加载器,这样就可以直接使用当前环境中的类和类库了。比如可以在groovy脚本中直接用获取spring bean的工具类:

在这里插入图片描述

而外部需要传进来参与规则执行的对象可以通过设置为binding的变量。

groovy脚本中抛出异常,和在java系统中抛出的异常类型信息一样,不会被包装,方便系统原有的异常处理机制统一处理:

在这里插入图片描述

dsl风格的规则声明

借助于groovy闭包和binding可以很轻松的实现dsl风格的声明:

在这里插入图片描述

这里的condition以及逻辑运算闭包还可以进一步优化成,不满足逻辑条件就不再执行,比如上面截图中的第一个condition满足条件,则后续的闭包不再解析执行,都可以自行控制实现。

弱类型的便利

原先在java代码中编写的各种校验规则,需要严格的静态类型检查还需要避免在运行时的空指针问题,而groovy天生就有类似于javascript的弱类型特性,且变量属性的访问,也不会有空指针问题,比如Integer类型的变量为null,使用<操作符;或者值为null的字符串变量调用equals

在弱语言中有一个特别需要注意的问题,变量可能存在全局污染,我们只要遵循这样的原则:在一个groovy脚本的头部声明变量时一定加上def,因为不用类型声明的变量会作为全局变量,可以在shell工具运行的多个脚本之间传递使用,因此要避免这一点。以下是笔者的练习:

在这里插入图片描述

校验规则的维护

对于简单的参数校验:非空、长度、正则等可以编写统一的groovy函数或者闭包,这样字段校验的脚本会变得非常简单,而对于复杂的关联性的校验只需要用java或者groovy脚本,在我们定义的condition中自由发挥即可。

在这里插入图片描述

通过这样的方式可以把规则成块的组织起来,包含了规则头部的声明块(变量的声明和初始化)、各个规则rule闭包声明的规则执行块。有了这样的结构后,可以把规则的定义从文件搬到数据库中,然后再通过web端的编辑权限进行修改维护(用支持groovy语法高亮的web编辑器),这样就可以做到不重启服务器的情况下,来动态更新业务规则,非常的省心。

基于事实推断的规则引擎实现

基于groovy强大的闭包语法特性,我们可以很轻松的实现笛卡尔积匹配方式的小型规则引擎,比如:

在这里插入图片描述


http://www.ppmy.cn/devtools/103296.html

相关文章

[Labview] 表格改值后单元格编辑功能,更改颜色、字体、颜色等

效果如下所示&#xff1a; 例子中演示了单元格变色&#xff0c;具体需要什么修改&#xff0c;在相同的位置进行操作即可。 检测到[鼠标释放]事件&#xff0c;则记录被选中的单元格。 使用[鼠标按下]事件也可以&#xff0c;不过我个人测试下来&#xff0c;[按下]的判断精准度不…

LoadBalancer负载均衡

一、概述 1.1、Ribbon目前也进入维护模式 Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡的工具。 简单的说&#xff0c;Ribbon是Netflix发布的开源项目&#xff0c;主要功能是提供客户端的软件负载均衡算法和服务调用。Ribbon客户端组件提供一系列完善的…

最新国内Docker 安装

一种方法是根据各个发行版的仓库&#xff0c;去安装Docker&#xff0c;这个版本一般比较老。 另一种方式是通过 根据脚本安装。所以给出下面信息。 Mirror 源 MirrorURL西北农林科技大学https://mirrors.nwafu.edu.cn/docker-ce/中国科学技术大学https://mirrors.ustc.edu.cn…

K8s之自动扩缩容

Kubernetes (K8s) 的动态扩缩容&#xff08;自动伸缩&#xff09;功能是集群管理中非常关键的一部分&#xff0c;能够根据工作负载的变化自动调整应用程序的副本数&#xff0c;以确保资源的高效利用和服务的稳定性。 K8s介绍文章 容器之k8s(Kubernetes)-CSDN博客 1. 动态扩缩容…

全民k歌怎么去水印保存?盘点分享3个无水印保存方法

在全民K歌的世界里&#xff0c;我们尽情展现音乐才华&#xff0c;但有时却会遇到一个棘手的问题&#xff1a;如何将歌曲视频无水印保存&#xff0c;以便自由分享到其他社交平台&#xff1f;为了解决这一难题&#xff0c;本文将为你盘点三种简单有效的无水印保存方法&#xff0c…

UE开发中的设计模式(四) —— 组合模式

面试中被面试官问到组合模式和继承有什么区别&#xff0c;给我问懵了&#xff0c;今天又仔细看了下&#xff0c;这不就是UE里的组件吗 >_< 文章目录 问题提出概述问题解决总结组合模式的优缺点继承的优缺点 问题提出 考虑这样一个场景&#xff0c;我们有一个敌人的基类&…

Prometheus之Blackbox监控

Prometheus之Blackbox监控 部署Blackbox 下载地址 https://github.com/prometheus/blackbox_exporter这里使用amd64架构的软件包&#xff0c;根据自己设备架构选择 右键复制链接地址 下载软件包 wget https://github.com/prometheus/blackbox_exporter/releases/download/v0…

flink 核心概念(个人总结)

flink是一个强大的分布式流处理和批处理框架&#xff0c;具有低延迟、容错性、高吞吐量和灵活的api优势。 在flink里面有七个核心概念。 数据流(datastream) flink将数据视为流&#xff0c;无论是实时的无界数据流还是有界的数据流。 a.无界数据流&#xff1a;实时生成的数据…