Java表达式和规则引擎的比较与考量

简介: Java表达式和规则引擎的比较与考量

  我们平时做项目主要面向企业客户的业务系统,企业的需求往往是多样化且复杂多变的,对接不同企业时会有不同的定制化的业务模型和流程。我们在业务系统中使用表达式引擎,集中配置管理业务规则,并实现实时决策和计算,可以提高系统的灵活性和响应能力,从而更好地满足业务的需求。

    规则引擎的一个好处是可以使业务规则和业务代码分离,从而降低维护难度,同时它还可以满足业务人员通过界面编写规则,这样就可以在没有开发人员参与的情况下建立规则,这种说法听起来似乎很有道理,但在实践中却很少行得通。首先,规则引擎有一定的学习成本,即使开发人员使用也需要进行专门的学习,更何况没有任何编程背景的业务人员,其次,其实现的复杂度也高,如果业务规则复杂,规则制定者对规则引擎内部隐藏的程序流程不了解,很可能会得到意想不到的结果,最后,有些规则引擎还存在性能瓶颈。

   本文对一些常用的java表达式和规则引擎进行比较,以便后续进行选择使用。

   1、Aviator表达式引擎

        Aviator是一个独立的表达式解析引擎,旨在执行数学和逻辑表达式。它提供了简单易用的语法和API,使得表达式解析和计算变得简单而直观。通过使用Aviator,我们可以高效地执行各种数学和逻辑运算,从而简化我们的代码逻辑。

      比如在flowable流程可以用下面进行流程条件的判断

/**
     * 校验el表达式
     *
     * @param map
     * @param expression
     * @return
     */
    public static boolean expressionResult(Map<String, Object> map, String expression) {
        Expression exp = AviatorEvaluator.compile(expression);
        final Object execute = exp.execute(map);
        return Boolean.parseBoolean(String.valueOf(execute));
    }

Aviator的特点

     高性能:Aviator被设计为高性能的表达式解析引擎。它使用解释器和JIT(Just-In-Time)编译器的混合模式,将表达式转换为优化的字节码,从而实现快速的表达式求值和计算。

灵活的表达式语法:Aviator的语法类似于Java语言,易于理解和编写表达式。它支持各种数学和逻辑运算符,以及丰富的内置函数,使得我们可以编写更灵活和功能强大的表达式。

自定义函数支持:Aviator允许我们定义自己的函数,并将其注册到引擎中供表达式使用。这样,我们可以根据实际需求扩展表达式的功能,满足特定的业务逻辑需求。

安全性和可扩展性:Aviator提供了安全的表达式执行环境,可以控制表达式对环境的访问权限。同时,它还支持自定义的上下文对象,可以在表达式求值过程中传递额外的上下文信息。

Aviator表达式引擎适用于多种应用场景:

规则引擎:通过Aviator,我们可以实现灵活的规则匹配和动态规则更新,例如金融领域的风控系统。

计算引擎:Aviator可以作为高性能的计算引擎,支持数学计算、数据分析和科学计算等任务。

动态

2、Fel轻量高效的表达式计算引擎

       Fel是开放的,引擎执行中的多个模块都可以扩展或替换。Fel的执行主要是通过函数实现,运算符(+、-等都是Fel函数),所有这些函数都是可以替换的,扩展函数也非常简单。

Fel有双引擎,同时支持解释执行和编译执行。可以根据性能要求选择执行方式。编译执行就是将表达式编译成字节码(生成java代码和编译模块都是可以扩展和替换的)

     通常情况下,Fel-0.7每秒可以执行千万次表达式(不包含编译时间)。速度是Jexl-2.0的20倍以上。目前还没有发现开源的表达式引擎比Fel快。

    比如在flowable的部分代码如下:

/**
     * 校验el表达示例
     *
     * @param map
     * @param expression
     * @return
     */
    public static Object result(Map<String, Object> map, String expression) {
        FelEngine fel = new FelEngineImpl();
        FelContext ctx = fel.getContext();
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            ctx.set(entry.getKey(), entry.getValue());
        }
        Object result = fel.eval(expression);
        return result;
    }

     目前我的项目里暂时使用了Fel。

 3、Easy Rules

      Easy Rules 是一款 Java 规则引擎,是轻量级的规则引擎API,它提供Rule抽象来创建带有条件和动作的规则,以及RulesEngine通过一组规则运行以测试条件和执行动作的API。

      Easy Rules 提供了规则抽象来创建带有条件和操作的规则,以及运行一组规则来评估条件和执行操作的RulesEngine API。

      但这个项目的问题是好久没维护了。

      下面是注解方式:

@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!");
  }
}

      链式编程方式如下:

Rule weatherRule = new RuleBuilder()
    .name("weather rule")
    .description("if it rains then take an umbrella")
    .when(facts -> facts.get("rain").equals(true))
    .then(facts -> System.out.println("It rains, take an umbrella!"))
    .build();

4、Drools

      Drools 是用Java语言编写的开放源码规则引擎,基于Apache协议,基于RETE算法,于2005年被JBoss收购。

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

     Drools通过 事实、规则和模式相互组合来完成工作,drools在开源规则引擎中使用率最广,但是在国内企业使用偏少,保险、支付行业使用稍多。

    这个是flowable系统内部本身采用的规则引擎。

    下面是一个flowable商用规则任务的实现

package org.flowable.engine.impl.bpmn.behavior;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.drools.KnowledgeBase;
import org.drools.runtime.StatefulKnowledgeSession;
import org.flowable.engine.delegate.BusinessRuleTaskDelegate;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.common.api.delegate.Expression;
import org.flowable.engine.impl.rules.RulesAgendaFilter;
import org.flowable.engine.impl.rules.RulesHelper;
import org.flowable.engine.impl.util.ProcessDefinitionUtil;
import org.flowable.engine.repository.ProcessDefinition;
/**
 * Activity implementation of the BPMN 2.0 business rule task.
 * 
 * @author Tijs Rademakers
 * @author Joram Barrez
 */
public class BusinessRuleTaskActivityBehavior extends TaskActivityBehavior implements BusinessRuleTaskDelegate {
    private static final long serialVersionUID = 1L;
    protected Set<Expression> variablesInputExpressions = new HashSet<>();
    protected Set<Expression> rulesExpressions = new HashSet<>();
    protected boolean exclude;
    protected String resultVariable;
    public BusinessRuleTaskActivityBehavior() {
    }
    @Override
    public void execute(DelegateExecution execution) {
        ProcessDefinition processDefinition = ProcessDefinitionUtil.getProcessDefinition(execution.getProcessDefinitionId());
        String deploymentId = processDefinition.getDeploymentId();
        KnowledgeBase knowledgeBase = RulesHelper.findKnowledgeBaseByDeploymentId(deploymentId);
        StatefulKnowledgeSession ksession = knowledgeBase.newStatefulKnowledgeSession();
        if (variablesInputExpressions != null) {
            Iterator<Expression> itVariable = variablesInputExpressions.iterator();
            while (itVariable.hasNext()) {
                Expression variable = itVariable.next();
                ksession.insert(variable.getValue(execution));
            }
        }
        if (!rulesExpressions.isEmpty()) {
            RulesAgendaFilter filter = new RulesAgendaFilter();
            Iterator<Expression> itRuleNames = rulesExpressions.iterator();
            while (itRuleNames.hasNext()) {
                Expression ruleName = itRuleNames.next();
                filter.addSuffic(ruleName.getValue(execution).toString());
            }
            filter.setAccept(!exclude);
            ksession.fireAllRules(filter);
        } else {
            ksession.fireAllRules();
        }
        Collection<Object> ruleOutputObjects = ksession.getObjects();
        if (ruleOutputObjects != null && !ruleOutputObjects.isEmpty()) {
            Collection<Object> outputVariables = new ArrayList<>();
            outputVariables.addAll(ruleOutputObjects);
            execution.setVariable(resultVariable, outputVariables);
        }
        ksession.dispose();
        leave(execution);
    }
    @Override
    public void addRuleVariableInputIdExpression(Expression inputId) {
        this.variablesInputExpressions.add(inputId);
    }
    @Override
    public void addRuleIdExpression(Expression inputId) {
        this.rulesExpressions.add(inputId);
    }
    @Override
    public void setExclude(boolean exclude) {
        this.exclude = exclude;
    }
    @Override
    public void setResultVariable(String resultVariableName) {
        this.resultVariable = resultVariableName;
    }
}


相关文章
|
23天前
|
Java API 开发者
Java中的Lambda表达式与Stream API的协同作用
在本文中,我们将探讨Java 8引入的Lambda表达式和Stream API如何改变我们处理集合和数组的方式。Lambda表达式提供了一种简洁的方法来表达代码块,而Stream API则允许我们对数据流进行高级操作,如过滤、映射和归约。通过结合使用这两种技术,我们可以以声明式的方式编写更简洁、更易于理解和维护的代码。本文将介绍Lambda表达式和Stream API的基本概念,并通过示例展示它们在实际项目中的应用。
|
25天前
|
Java API 开发者
Java中的Lambda表达式:简洁代码的利器####
本文探讨了Java中Lambda表达式的概念、用途及其在简化代码和提高开发效率方面的显著作用。通过具体实例,展示了Lambda表达式如何在Java 8及更高版本中替代传统的匿名内部类,使代码更加简洁易读。文章还简要介绍了Lambda表达式的语法和常见用法,帮助开发者更好地理解和应用这一强大的工具。 ####
|
27天前
|
并行计算 Java 编译器
深入理解Java中的Lambda表达式
在Java 8中引入的Lambda表达式,不仅简化了代码编写,还提升了代码可读性。本文将带你探索Lambda表达式背后的逻辑与原理,通过实例展示如何高效利用这一特性优化你的程序。
|
1月前
|
搜索推荐 Java API
探索Java中的Lambda表达式
本文将深入探讨Java 8引入的Lambda表达式,这一特性极大地简化了代码编写,提高了程序的可读性。通过实例分析,我们将了解Lambda表达式的基本概念、使用场景以及如何优雅地重构传统代码。文章不仅适合初学者,也能帮助有经验的开发者加深对Lambda表达式的理解。
|
1月前
|
Java
探索Java中的Lambda表达式
【10月更文挑战第37天】本文将带你深入理解Java的Lambda表达式,从基础语法到高级特性,通过实例讲解其在函数式编程中的应用。我们还将探讨Lambda表达式如何简化代码、提高开发效率,并讨论其在实际项目中的应用。
|
1月前
|
Java API
Java中的Lambda表达式与函数式编程####
【10月更文挑战第29天】 本文将深入探讨Java中Lambda表达式的实现及其在函数式编程中的应用。通过对比传统方法,我们将揭示Lambda如何简化代码、提高可读性和维护性。文章还将展示一些实际案例,帮助读者更好地理解和应用Lambda表达式。 ####
|
1月前
|
JSON 自然语言处理 Java
这款轻量级 Java 表达式引擎,真不错!
AviatorScript 是一个高性能、轻量级的脚本语言,基于 JVM(包括 Android 平台)。它支持数字、字符串、正则表达式、布尔值等基本类型,以及所有 Java 运算符。主要特性包括函数式编程、大整数和高精度运算、完整的脚本语法、丰富的内置函数和自定义函数支持。适用于规则判断、公式计算、动态脚本控制等场景。
|
1月前
|
Java API 开发者
Java中的Lambda表达式与函数式编程####
在Java的演变过程中,Lambda表达式和函数式编程的引入无疑是一次重大的飞跃。本文将深入探讨Lambda表达式的定义、用法及优势,并结合实例说明如何在Java中利用Lambda表达式进行函数式编程。通过对比传统编程方式,揭示Lambda表达式如何简化代码、提高开发效率和可维护性。 ####
|
22天前
|
安全 Java API
Java中的Lambda表达式:简化代码的现代魔法
在Java 8的发布中,Lambda表达式的引入无疑是一场编程范式的革命。它不仅让代码变得更加简洁,还使得函数式编程在Java中成为可能。本文将深入探讨Lambda表达式如何改变我们编写和维护Java代码的方式,以及它是如何提升我们编码效率的。
|
2月前
|
自然语言处理 安全 Java
Aviator Java 表达式引擎
AviatorScript 是一门高性能、轻量级寄宿于 JVM 之上的脚本语言。
63 10