当前位置: 首页 > news >正文

实现动态业务规则的方法(Java)

实现动态业务规则的方法(Java)

企业信息化系统核心在于业务领域的概念模型及于此基础上复杂多变的业务规则,实现中通常抽象规则的接口方法,使用继承或策略等设计模式实现不同的业务规则的实现。领域的概念模型在特定领域是稳定的,比如,采购场景下的报价模型包括是:报价供应商、价格、税率、汇率、报价标的物有效数量、有效地点、有效时间、送货时间等业务概念。从定标规则,从众多报价中选择最终报价的规则则在不同企业,不同商品都有则不同,如按最低价、按最高价(卖出场景)、按最快送货、按供应商评分等等可能的选择方式,在每次规则变化的时候重新迭代实现是一种方式,编写业务规则并支持动态替换执行是另一种选择。 本文介绍了Java实现动态业务规则几种方法。

Java动态类装载

基本流程如下:

  1. 将新业务以Java实现, 并编译成class文件,上传至类路径下。
  2. 实现ClassLoader在运行时加载类。
  3. 使用放射或Spring容器Bean管理等方法使用新的类实现。

Spring 中动态加载类替换Bean的一个示例过程:

//加载新的实现类

Class<?> type = loadClass(classPath, className);

//销毁原注册旧bean

listableBeanFactory.destroySingleton(beanName);

//创建新实现类的实例

T obj = listableBeanFactory.createBean(type);

//注册新的实例到容器中

listableBeanFactory.registerSingleton(beanName, obj);

脚本引擎

Java 内置的Nashorn引擎支持在Java中执行JavaScript 代码。ScriptEngineManager是Nashorn引擎的API。使用方法如下:

  1. 获取脚本引擎
  2. 设置参数
  3. 编译JavaScript脚本。
  4. 执行编译后的JavaScript脚本获取结果。也可以直接跳过编译,直接执行原始脚本,这样会在每次执行都重新编译,会带来极大的性能损耗问题。

示例代码如下:

ScriptEngineManager manager = new ScriptEngineManager();

//通过后缀名获取引擎, getEngineByxxx方法提供了通过不同方式获取引擎的方法

ScriptEngine engine = manager.getEngineByExtension("js");

//设置参数

engine.put("param1", "test");

Compilable compEngine = (Compilable) engine;

ompiledScript script = compEngine.compile("

var output = param1;

return output;

");

//执行脚本并获取结果

String result = script.eval()

引擎也支持将脚本编译为方法供Java代码调用,但从耦合角度并不是很好的实践,脚本应尽可能的实现单一职能、独立的规则。而不是耦合到一个复杂逻辑中。

表达式引擎

表达式引擎是根据传入参数执行计算公式或特定表达式并返回结果的工具。表达式引擎通道都使用类java的语法规则,可以方便的和java运行时不同类型的数据对象进行交互,强调高效的性能。另外也有源自金融领域,专门提供各类数学计算公式的表达式引擎。 如Express4j。表达式引擎和脚本引擎比起来更轻量化,更强调性能。

表达式引擎的应用场景如定义一个风险规则表达式,当执行业务逻辑前对输入数据是进行检查。

在Spring 项目推荐使用SPEL进行表达式计算。

引擎

特点

Fel

轻量级的、高效的表达式计算引擎。

OGNL

通过简单一致的表达式语法,可以存取对象属性,调用对象的方法,遍历整个对象,实现字段类型转化等功能。

SpEL

Spring表达式语言(简称“SpEL”)支持在运行时查询和操作对象。属于Spring技术体系,可以很好融合与Spring项目,比如操作Bean对象等,应用于注解、Bean定义等。

https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#expressions

Expression4j

Expression4js使用JAVA实现;是专门针对金融公司的指标数据计算的一个量化跟踪引擎项目中进行抽象而来的一个子项目。可以直接支持数学公式的计算。

https://expression4j.sourceforge.net/

Aviator

Aviator是一个高性能、轻量级的java语言实现的表达式求值引擎,主要用于各种表达式的动静求值。

http://fnil.net/aviator/

QLExpress

为阿里的电商业务规则、表达式(布尔组合)、特殊数学公式计算(高精度)、语法分析、脚本二次定制等强需求而设计的一门动态脚本引擎解析工具。具有线程安全、高效、弱类型、安全控制等特点

https://github.com/alibaba/QLExpress

MVEL

MVEL为 MVFLEX Expression Language(MVFLEX表达式语言)的缩写,它是一种动态/静态的可嵌入的表达式语言和为Java平台提供Runtime执行功能。

https://github.com/mvel/mvel

Fel 样例:

FelEngine fel = new FelEngineImpl();

Object result = fel.eval(“3000*10+7500”);

System.out.println(result);

Ognl样例:

Ognl.getValue("#user.name", context, user)

Express4j 样例:

Expression expression = ExpressionFactory.createExpression("f()=abs(-3)");

expression.evaluate(null).getRealValue();

SPEL 样例:

SpelExpressionParser parser = new SpelExpressionParser();

StandardEvaluationContext standardEvaluationContext = new StandardEvaluationContext();

standardEvaluationContext.setBeanResolver(new BeanFactoryResolver(applicationContext));

parser.parseExpression("@testService.test()").getValue(standardEvaluationContext, Boolean.class);

规则引擎

脚本引擎提供的是脚本执行能力,表达式引擎提供的是表达式计算能力,规则引擎是供以规则为核心的编程模型。规则引擎通常支持多种表达式语言引擎作为规则条件的执行引擎。

脚本引擎、表达式引擎是工具,规则引擎是框架或者甚至是产品(Drools)。

Drools

Drools是一种业务规则管理系统(BRMS)解决方案。它提供了一个核心业务规则引擎(BRE)、一个创建和管理规则web应用程序(Drools Workbench)、对Decision Model and Notation (DMN)提供了一致性级别中Level3的支持,同时提供了IDE的开发插件。

    Drools是一个重量级的规则引擎产品,很多像金融行业、电信行业的大公司都使用它作为规则引擎。

项目官网:Drools - Drools - Business Rules Management System (Java™, Open Source)
项目地址:GitHub - kiegroup/drools: Mirror of https://github.com/apache/incubator-kie-drools

在项目中如果仅仅是使用Drools的规则引擎核心BRE,可以引入依赖Maven使用,也可以使用BRMS的整套解决方案以Drools为核心构建业务系统。
 

样例:

  1. 规则文件: 对有效期内账户对象的存取行为进行余额增加或扣减。

package org.drools.examples.cashflow;

dialect  "mvel"

rule "Increase balance for AccountPeriod Credits"

when

   // 模式匹配:到工作内存中查找特定类型对象,可以提供匹配表达式,如purchaseQuantity == 1

   // 如果条件成立,$ap,一般以$开头,和fact对象区分开

   ap : AccountPeriod( )

   $acc : Account( )

   cf : CashFlow( type == CashFlowType.CREDIT,

             accountNo == $acc.accountNo,

             date >= ap.start && <= ap.end )

then

   $acc.balance = $acc.balance + cf.amount;

end

rule "Decrease balance for AccountPeriod Debits"

when

   ap : AccountPeriod( )

   $acc : Account( )

   cf : CashFlow( type == CashFlowType.DEBIT, accountNo == $acc.accountNo, date >= ap.start && <= ap.end )

then

   $acc.balance = $acc.balance - cf.amount;

end

end

  1. 触发执行引擎

KieContainer kc = KieServices.Factory.get().getKieClasspathContainer();

KieSession ksession = kc.newKieSession( "CashFlowKS");

AccountPeriod acp = new AccountPeriod(date( "2013-01-01"), date( "2013-03-31"));

Account ac = new Account(1, 0);

CashFlow cf1 = new CashFlow(date( "2013-01-12"), 100, CashFlowType.CREDIT, 1 );

FactHandle fh = ksession.insert( acp );

ksession.insert( ac );

ksession.insert( cf1 );

ksession.fireAllRules();

EasyRules

EasyRules是一个轻量的规则引擎框架, 它提供了Rule抽象来创建带有条件和操作的规则,以及使用API:RulesEngine。

主要特性:

  1. 轻量化的库,易于使用的API
  2. 提供基于注解的,POJO模型。
  3. 为Java提供为定义业务规则的良好抽象。
  4. 可以通过简单规则组合成为复杂规则。
  5. 可以使用表达式语言定义规则(如SPEL,MVEL,见表达式引擎)

项目地址:https://github.com/j-easy/easy-rules

样例:

  1. 通过类注解定义规则:@Rule、@Condition、@Action

Rule: 当Ccondition满足,则执行Action

@Rule(name = "weather rule", description = "if it rains then take an umbrella")

public class WeatherRule {

    @Condition

    public boolean itRains(@Fact("rain") boolean rain) {

        return rain;

    }

    @Action

    public void takeAnUmbrella() {

        System.out.println("It rains, take an umbrella!");

    }

}

  1. 通过文件定制规则

name: "weather rule"

description: "if it rains then take an umbrella"

condition: "rain == true"

actions:

  - "System.out.println(\"It rains, take an umbrella!\");"

  1. 执行规则

// define facts

Facts facts = new Facts();

facts.put("rain", true);

// define rules

MVELRuleFactory ruleFactory = new MVELRuleFactory(new YamlRuleDefinitionReader());

Rule weatherRule = ruleFactory.createRule(new FileReader("weather-rule.yml"));

Rules rules = new Rules();

rules.register(weatherRule);

// fire rules on known facts

RulesEngine rulesEngine = new DefaultRulesEngine();

rulesEngine.fire(rules, facts);

相关文章:

实现动态业务规则的方法(Java)

实现动态业务规则的方法&#xff08;Java&#xff09; 企业信息化系统核心在于业务领域的概念模型及于此基础上复杂多变的业务规则&#xff0c;实现中通常抽象规则的接口方法&#xff0c;使用继承或策略等设计模式实现不同的业务规则的实现。领域的概念模型在特定领域是稳定的…...

leetcodeTOP100(26)两数相加

给你两个 非空 的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的&#xff0c;并且每个节点只能存储 一位 数字。 请你将两个数相加&#xff0c;并以相同形式返回一个表示和的链表。 你可以假设除了数字 0 之外&#xff0c;这两个数都不会以 0 …...

performance_schema

插桩名称的最左边部分表示插桩类型&#xff0c;其余部分从左到右依次表示到特定的子系统 mysql> select * from performance_schema.setup_instruments where documentation is not null limit 5,5\G; *************************** 1. row ***************************NAME:…...

全新UI基于Thinkphp的最新自助打印系统/云打印小程序源码/附教程

这是一款全新的基于Thinkphp的最新自助打印系统&#xff0c;最新UI界面设计的云打印小程序源码&#xff0c;带有简单的教程。 下载地址&#xff1a;https://bbs.csdn.net/topics/617324130...

Android 13.0 framework层系统手势增加上滑手势home事件功能(相当于Home键)

1.概述 在13.0的定制化开发系统手势功能的时候,客户需求要求在上滑手势的时候,在底部上滑时候进入系统桌面,也就是增加 home键功能,所以就需要分析相关的系统手势上滑事件,然后添加home事件这样 就可以实现这个功能了 2.framework层系统手势增加上滑手势home事件功能的核…...

webp格式及其转成

"WebP" 是一种现代的图像压缩格式&#xff0c;由谷歌公司开发。它旨在提供高质量的图像压缩&#xff0c;同时减小图像文件的大小&#xff0c;从而加快网络加载速度。WebP 格式通常使用 ".webp" 扩展名来标识。 WebP 图像格式主要有以下几个特点和优点&…...

echo cat find grep命令

目录 cat echo grep find cat cat命令可以理解为英文单词concatenate的缩写&#xff0c;其功能是连接多个文件并且打印到屏幕输出&#xff0c;或者重定向到指定文件中。此命令常用于显示单个文件内容&#xff0c;或者将几个文件内容连接起来一起显示&#xff0c;还可以从标…...

Linux学习第20天:Linux按键输入驱动开发: 大道至简 量入为出

Linux版本号4.1.15 芯片I.MX6ULL 大叔学Linux 品人间百味 思文短情长 中国文化博大精深&#xff0c;太极八卦&#xff0c;阴阳交合&#xff0c;变化无穷。在程序的开发中也是这样&#xff0c;数字0和1也是同样的道理。就本节来说&am…...

WordPress主题开发( 七)之—— 模版文件继承规则

WordPress主题开发&#xff08; 七&#xff09;之—— 模版文件继承规则 概述模板文件层次结构示例可视化概述层次结构详细信息主页显示首页显示单文章页面单页分类目录标签自定义分类自定义文章类型作者显示日期搜索结果404&#xff08;未找到&#xff09;附件嵌入功能非ASCII…...

Simulink 封装

快捷键&#xff1a; Edit Mask&#xff1a;CtrlM Look Under Mask&#xff1a;CtrlU 封装之后的模型&#xff1a; Edit Mask界面&#xff1a; 双击模块后的提示界面&#xff1a; 封装的模块内部&#xff1a;...

【AI视野·今日Robot 机器人论文速览 第三十六期】Tue, 19 Sep 2023

AI视野今日CS.Robotics 机器人学论文速览 Tue, 19 Sep 2023 (showing first 100 of 112 entries) Totally 112 papers &#x1f449;上期速览✈更多精彩请移步主页 Interesting: &#x1f4da;In-Hand Object Rotation, RotateIt 提出了一种基于视觉与触觉的物体旋转朝向的方法…...

Java随笔

动态SQL 是指根据不同的条件或参数生成不同的SQL语句的技术。在实际开发中&#xff0c;我们经常需要根据用户的输入或其他条件来生成不同的SQL语句&#xff0c;动态SQL就能满足这个需求。 在Java中&#xff0c;使用MyBatis作为ORM框架时&#xff0c;可以通过在Mapper.xml文件…...

ARINC825规范简介

ARINC825规范简介 机载CAN网络通用标准 ARINC825规范全称为机载CAN网络通用标准&#xff08;The General Standardization of CAN for Airborne Use&#xff09;。顾名思义&#xff0c;ARINC825规范是建立在CAN物理网络基础上的高层规范。CAN网络使用共享的双绞电缆传输数据&…...

SQLAlchemy列参数的使用和query函数的使用

目录 Column常用参数 代码演示 代码刨析 query函数的使用 基本用法 常见用法示例 查询所有记录 根据条件查询 查询第一条符合条件的记录 查询特定列的值 添加排序规则 使用聚合函数 连接查询 使用filter_by Column常用参数 primary_key&#xff1a;True设置某个字…...

产权未转移登记的离婚析产协议不能对抗债权人

债权人代位析产纠纷作为一个新的民事案由&#xff0c;是民事执行阶段中债务人不能到期清偿债务&#xff0c;又怠于分割共同财产或以诉讼方式分割共同财产&#xff0c;而由债权人请求代替债务人向其他共有人提出分割财产以实现债权的诉讼。债权人代位析产&#xff0c;增加了债权…...

python+nodejs+php+springboot+vue 导师双选系统

为了直观显示系统的功能&#xff0c;运用用例图这样的工具显示分析的结果。分析的导师功能如下。导师管理导师选择信息&#xff0c;管理项目&#xff0c;管理项目提交并对学员提交的项目进行指导。 为了直观显示系统的功能&#xff0c;运用用例图这样的工具显示分析的结果。分析…...

paddle2.3-基于联邦学习实现FedAVg算法

目录 1. 联邦学习介绍 2. 实验流程 3. 数据加载 4. 模型构建 5. 数据采样函数 6. 模型训练 1. 联邦学习介绍 联邦学习是一种分布式机器学习方法&#xff0c;中心节点为server&#xff08;服务器&#xff09;&#xff0c;各分支节点为本地的client&#xff08;设备&#…...

伺服丝杠系统常用运算功能块

这篇博客主要介绍伺服、丝杠系统常用的运算功能块,其它相关运算可以查看下面文章链接: 信捷PLC脉冲频率、位移、转速相关计算(C语言编程应用)_RXXW_Dor的博客-CSDN博客里工业控制张力控制无处不在,也衍生出很多张力控制专用控制器,磁粉制动器等,本篇博客主要讨论PLC的张力…...

【Vue】模板语法,事件处理器及综合案例、自定义组件、组件通信

一、事件处理器 我们之前事件监听可以使用v-on 指令 1、事件修饰符 在Vue中我们通过由点(.)表示的指令后缀来调用修饰符&#xff0c;比如&#xff1a; .stop&#xff1a;阻止事件冒泡。当事件触发时&#xff0c;该修饰符将停止事件进一步冒泡到父元素。相当于调用了 event.stop…...

从0开始写中国象棋-创建棋盘与棋子

从控制台版本开始 考虑到象棋程序&#xff0c;其实就是数据结构与算法实现。 所以和界面相关的QT部分我们先放一放。 我们从控制台版本开始。这样大家更容易接受&#xff0c;也不影响开发。 后面我们会把控制台嫁接到QT上完成完整的游戏&#xff0c;那时候自然就水到渠成了…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…...

学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2

每日一言 今天的每一份坚持&#xff0c;都是在为未来积攒底气。 案例&#xff1a;OLED显示一个A 这边观察到一个点&#xff0c;怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 &#xff1a; 如果代码里信号切换太快&#xff08;比如 SDA 刚变&#xff0c;SCL 立刻变&#…...

Rapidio门铃消息FIFO溢出机制

关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系&#xff0c;以下是深入解析&#xff1a; 门铃FIFO溢出的本质 在RapidIO系统中&#xff0c;门铃消息FIFO是硬件控制器内部的缓冲区&#xff0c;用于临时存储接收到的门铃消息&#xff08;Doorbell Message&#xff09;。…...

代理篇12|深入理解 Vite中的Proxy接口代理配置

在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...

Java 二维码

Java 二维码 **技术&#xff1a;**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...

安卓基础(aar)

重新设置java21的环境&#xff0c;临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的&#xff1a; MyApp/ ├── app/ …...

Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习)

Aspose.PDF 限制绕过方案&#xff1a;Java 字节码技术实战分享&#xff08;仅供学习&#xff09; 一、Aspose.PDF 简介二、说明&#xff08;⚠️仅供学习与研究使用&#xff09;三、技术流程总览四、准备工作1. 下载 Jar 包2. Maven 项目依赖配置 五、字节码修改实现代码&#…...

AGain DB和倍数增益的关系

我在设置一款索尼CMOS芯片时&#xff0c;Again增益0db变化为6DB&#xff0c;画面的变化只有2倍DN的增益&#xff0c;比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析&#xff1a; 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...

现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?

现有的 Redis 分布式锁库&#xff08;如 Redisson&#xff09;相比于开发者自己基于 Redis 命令&#xff08;如 SETNX, EXPIRE, DEL&#xff09;手动实现分布式锁&#xff0c;提供了巨大的便利性和健壮性。主要体现在以下几个方面&#xff1a; 原子性保证 (Atomicity)&#xff…...

windows系统MySQL安装文档

概览&#xff1a;本文讨论了MySQL的安装、使用过程中涉及的解压、配置、初始化、注册服务、启动、修改密码、登录、退出以及卸载等相关内容&#xff0c;为学习者提供全面的操作指导。关键要点包括&#xff1a; 解压 &#xff1a;下载完成后解压压缩包&#xff0c;得到MySQL 8.…...