欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java中動(dòng)態(tài)規(guī)則的實(shí)現(xiàn)方式示例詳解

 更新時(shí)間:2020年08月25日 10:17:47   作者:阿凡盧  
這篇文章主要介紹了Java中動(dòng)態(tài)規(guī)則的實(shí)現(xiàn)方式,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

背景

業(yè)務(wù)系統(tǒng)在應(yīng)用過(guò)程中,有時(shí)候要處理“經(jīng)常變化”的部分,這部分需求可能是“業(yè)務(wù)規(guī)則”,也可能是“不同的數(shù)據(jù)處理邏輯”,這部分動(dòng)態(tài)規(guī)則的問(wèn)題,往往需要可配置,并對(duì)性能和實(shí)時(shí)性有一定要求。

Java不是解決動(dòng)態(tài)層問(wèn)題的理想語(yǔ)言,在實(shí)踐中發(fā)現(xiàn)主要有以下幾種方式可以實(shí)現(xiàn):

  • 表達(dá)式語(yǔ)言(expression language)
  • 動(dòng)態(tài)語(yǔ)言(dynamic/script language language),如Groovy
  • 規(guī)則引擎(rule engine)

表達(dá)式語(yǔ)言

Java Unified Expression Language,簡(jiǎn)稱JUEL,是一種特殊用途的編程語(yǔ)言,主要在JavaWeb應(yīng)用程序用于將表達(dá)式嵌入到web頁(yè)面。Java規(guī)范制定者和Java Web領(lǐng)域技術(shù)專家小組制定了統(tǒng)一的表達(dá)式語(yǔ)言。JUEL最初包含在JSP2.1規(guī)范JSR-245中,后來(lái)成為Java EE 7的一部分,改在JSR-341中定義。

主要的開源實(shí)現(xiàn)有:OGNL,MVEL,SpEL,JUELJava Expression Language (JEXL),JEvalJakarta JXPath等。

這里主要介紹在實(shí)踐中使用較多的MVEL、OGNL和SpEL。

OGNL(Object Graph Navigation Library)

在Struts 2 的標(biāo)簽庫(kù)中都是使用OGNL表達(dá)式訪問(wèn)ApplicationContext中的對(duì)象數(shù)據(jù),簡(jiǎn)單示例:

Foo foo = new Foo();
foo.setName("test");
Map<String, Object> context = new HashMap<String, Object>();
context.put("foo",foo);
String expression = "foo.name == 'test'";
try {
 Boolean result = (Boolean) Ognl.getValue(expression,context);
 System.out.println(result);
} catch (OgnlException e) {
 e.printStackTrace();
}

MVEL

MVEL最初作為Mike Brock創(chuàng)建的 Valhalla項(xiàng)目的表達(dá)式計(jì)算器(expression evaluator),相比最初的OGNL、JEXL和JUEL等項(xiàng)目,而它具有遠(yuǎn)超它們的性能、功能和易用性 - 特別是集成方面。它不會(huì)嘗試另一種JVM語(yǔ)言,而是著重解決嵌入式腳本的問(wèn)題。

MVEL主要使用在Drools,是Drools規(guī)則引擎不可分割的一部分。

MVEL語(yǔ)法較為豐富,不僅包含了基本的屬性表達(dá)式,布爾表達(dá)式,變量復(fù)制和方法調(diào)用,還支持函數(shù)定義,詳情參見(jiàn)MVEL Language Guide

MVEL在執(zhí)行語(yǔ)言時(shí)主要有解釋模式(Interpreted Mode)和編譯模式(Compiled Mode)兩種:

解釋模式(Interpreted Mode)是一個(gè)無(wú)狀態(tài)的,動(dòng)態(tài)解釋執(zhí)行,不需要負(fù)載表達(dá)式就可以執(zhí)行相應(yīng)的腳本。編譯模式(Compiled Mode)需要在緩存中產(chǎn)生一個(gè)完全規(guī)范化表達(dá)式之后再執(zhí)行。

//解釋模式
Foo foo = new Foo();
foo.setName("test");
Map context = new HashMap();
String expression = "foo.name == 'test'";
VariableResolverFactory functionFactory = new MapVariableResolverFactory(context);
context.put("foo",foo);
Boolean result = (Boolean) MVEL.eval(expression,functionFactory);
System.out.println(result);

//編譯模式
Foo foo = new Foo();foo.setName("test");
Map context = new HashMap();
String expression = "foo.name == 'test'";
VariableResolverFactory functionFactory = new MapVariableResolverFactory(context);context.put("foo",foo);
Serializable compileExpression = MVEL.compileExpression(expression);

SpEL

SpEl(Spring表達(dá)式語(yǔ)言)是一個(gè)支持查詢和操作運(yùn)行時(shí)對(duì)象導(dǎo)航圖功能的強(qiáng)大的表達(dá)式語(yǔ)言。 它的語(yǔ)法類似于傳統(tǒng)EL,但提供額外的功能,最出色的就是函數(shù)調(diào)用和簡(jiǎn)單字符串的模板函數(shù)。SpEL類似于Struts2x中使用的OGNL表達(dá)式語(yǔ)言,能在運(yùn)行時(shí)構(gòu)建復(fù)雜表達(dá)式、存取對(duì)象圖屬性、對(duì)象方法調(diào)用等等,并且能與Spring功能完美整合,如能用來(lái)配置Bean定義。

SpEL主要提供基本表達(dá)式、類相關(guān)表達(dá)式及集合相關(guān)表達(dá)式等,詳細(xì)參見(jiàn)Spring 表達(dá)式語(yǔ)言 (SpEL)。

類似與OGNL,SpEL具有expression(表達(dá)式),Parser(解析器),EvaluationContext(上下文)等基本概念;類似與MVEL,SpEl也提供了解釋模式和編譯模式兩種運(yùn)行模式。

//解釋器模式
Foo foo = new Foo();
foo.setName("test");
// Turn on:
// - auto null reference initialization
// - auto collection growing
SpelParserConfiguration config = new SpelParserConfiguration(true,true);
ExpressionParser parser = new SpelExpressionParser(config);
String expressionStr = "#foo.name == 'test'";
StandardEvaluationContext context = new StandardEvaluationContext();
context.setVariable("foo",foo);
Expression expression = parser.parseExpression(expressionStr);
Boolean result = expression.getValue(context,Boolean.class);

//編譯模式
config = new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE, RunSpel.class.getClassLoader());
parser = new SpelExpressionParser(config);
context = new StandardEvaluationContext();
context.setVariable("foo",foo);
expression = parser.parseExpression(expressionStr);
result = expression.getValue(context,Boolean.class);

規(guī)則引擎

一些規(guī)則引擎(rule engine):aviator,easy-rulesdrools,esper

aviator

AviatorScript是一門高性能、輕量級(jí)寄宿于 JVM 之上的腳本語(yǔ)言。

使用場(chǎng)景包括:

  • 規(guī)則判斷及規(guī)則引擎
  • 公式計(jì)算
  • 動(dòng)態(tài)腳本控制
  • 集合數(shù)據(jù) ELT 等
public class Test {
 public static void main(String[] args) {
  String expression = "a+(b-c)>100";
  // 編譯表達(dá)式
  Expression compiledExp = AviatorEvaluator.compile(expression);

  Map<String, Object> env = new HashMap<>();
  env.put("a", 100.3);
  env.put("b", 45);
  env.put("c", -199.100);

  // 執(zhí)行表達(dá)式
  Boolean result = (Boolean) compiledExp.execute(env);
  System.out.println(result);
 }
}

easy-rules

Easy Rules is a Java rules engine。

使用POJO定義規(guī)則:

@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();

支持使用表達(dá)式語(yǔ)言(MVEL/SpEL)來(lái)定義規(guī)則:

weather-rule.ymlexample:

name: "weather rule"
description: "if it rains then take an umbrella"
condition: "rain == true"
actions:
 - "System.out.println(\"It rains, take an umbrella!\");"
MVELRuleFactory ruleFactory = new MVELRuleFactory(new YamlRuleDefinitionReader());
Rule weatherRule = ruleFactory.createRule(new FileReader("weather-rule.yml"));

觸發(fā)規(guī)則:

public class Test {
 public static void main(String[] args) {
  // define facts
  Facts facts = new Facts();
  facts.put("rain", true);

  // define rules
  Rule weatherRule = ...
  Rules rules = new Rules();
  rules.register(weatherRule);

  // fire rules on known facts
  RulesEngine rulesEngine = new DefaultRulesEngine();
  rulesEngine.fire(rules, facts);
 }
}

drools

An open source rule engine,DMN engineand complex event processing (CEP) engine for Java and the JVM Platform.

定義規(guī)則:

import com.lrq.wechatDemo.domain.User // 導(dǎo)入類
dialect "mvel"
rule "age" // 規(guī)則名,唯一
 when
  $user : User(age<15 || age>60) //規(guī)則的條件部分
 then
  System.out.println("年齡不符合要求!");
end

參考例子:

public class TestUser {
 private static KieContainer container = null;
 private KieSession statefulKieSession = null;

 @Test
 public void test(){
  KieServices kieServices = KieServices.Factory.get();
  container = kieServices.getKieClasspathContainer();
  statefulKieSession = container.newKieSession("myAgeSession");
  User user = new User("duval yang",12);
  statefulKieSession.insert(user);
  statefulKieSession.fireAllRules();
  statefulKieSession.dispose();
 }
}

esper

Esper is a component for complex event processing (CEP), streaming SQL and event series analysis, available for Java as Esper, and for .NET as NEsper.

一個(gè)例子:

public class Test {
 public static void main(String[] args) throws InterruptedException {
  EPServiceProvider epService = EPServiceProviderManager.getDefaultProvider();
 
  EPAdministrator admin = epService.getEPAdministrator();
 
  String product = Apple.class.getName();
  String epl = "select avg(price) from " + product + ".win:length_batch(3)";
 
  EPStatement state = admin.createEPL(epl);
  state.addListener(new AppleListener());
 
  EPRuntime runtime = epService.getEPRuntime();
 
  Apple apple1 = new Apple();
  apple1.setId(1);
  apple1.setPrice(5);
  runtime.sendEvent(apple1);
 
  Apple apple2 = new Apple();
  apple2.setId(2);
  apple2.setPrice(2);
  runtime.sendEvent(apple2);
 
  Apple apple3 = new Apple();
  apple3.setId(3);
  apple3.setPrice(5);
  runtime.sendEvent(apple3);
 }
}

drools和esper都是比較重的規(guī)則引擎,詳見(jiàn)其官方文檔。

動(dòng)態(tài)JVM語(yǔ)言

Groovy

Groovy除了Gradle上的廣泛應(yīng)用之外,另一個(gè)大范圍的使用應(yīng)該就是結(jié)合Java使用動(dòng)態(tài)代碼了。Groovy的語(yǔ)法與Java非常相似,以至于多數(shù)的Java代碼也是正確的Groovy代碼。Groovy代碼動(dòng)態(tài)的被編譯器轉(zhuǎn)換成Java字節(jié)碼。由于其運(yùn)行在JVM上的特性,Groovy可以使用其他Java語(yǔ)言編寫的庫(kù)。

Groovy可以看作給Java靜態(tài)世界補(bǔ)充動(dòng)態(tài)能力的語(yǔ)言,同時(shí)Groovy已經(jīng)實(shí)現(xiàn)了java不具備的語(yǔ)言特性:

  • 函數(shù)字面值;
  • 對(duì)集合的一等支持;
  • 對(duì)正則表達(dá)式的一等支持;
  • 對(duì)xml的一等支持;

Groovy作為基于JVM的語(yǔ)言,與表達(dá)式語(yǔ)言存在語(yǔ)言級(jí)的不同,因此在語(yǔ)法上比表達(dá)還是語(yǔ)言更靈活。Java在調(diào)用Groovy時(shí),都需要將Groovy代碼編譯成Class文件。

Groovy 可以采用GroovyClassLoader、GroovyShell、GroovyScriptEngine和JSR223等方式與Java語(yǔ)言集成。

一個(gè)使用GroovyClassLoader動(dòng)態(tài)對(duì)json對(duì)象進(jìn)行filter的例子:

public class GroovyFilter implements Filter {
 private static String template = "" +
   "package com.alarm.eagle.filter;" +
   "import com.fasterxml.jackson.databind.node.ObjectNode;" +
   "def match(ObjectNode o){[exp]}";

 private static String method = "match";

 private String filterExp;

 private transient GroovyObject filterObj;

 public GroovyFilter(String filterExp) throws Exception {
  ClassLoader parent = Thread.currentThread().getContextClassLoader();
  GroovyClassLoader classLoader = new GroovyClassLoader(parent);
  Class clazz = classLoader.parseClass(template.replace("[exp]", filterExp));
  filterObj = (GroovyObject)clazz.newInstance();
 }

 public boolean filter(ObjectNode objectNode) {
  return (boolean)filterObj.invokeMethod(method, objectNode);
 }
}

Java每次調(diào)用Groovy代碼都會(huì)將Groovy編譯成Class文件,因此在調(diào)用過(guò)程中會(huì)出現(xiàn)JVM級(jí)別的問(wèn)題。如使用GroovyShell的parse方法導(dǎo)致perm區(qū)爆滿的問(wèn)題,使用GroovyClassLoader加載機(jī)制導(dǎo)致頻繁gc問(wèn)題和CodeCache用滿,導(dǎo)致JIT禁用問(wèn)題等,相關(guān)問(wèn)題可以參考深入學(xué)習(xí)java中的Groovy 和 Scala 類。

參考:

Java各種規(guī)則引擎:https://www.jianshu.com/p/41ea7a43093c

Java中使用動(dòng)態(tài)代碼:http://brucefengnju.github.io/post/dynamic-code-in-java/

量身定制規(guī)則引擎,適應(yīng)多變業(yè)務(wù)場(chǎng)景:https://my.oschina.net/yygh/blog/616808?p=1

總結(jié)

到此這篇關(guān)于Java中動(dòng)態(tài)規(guī)則的實(shí)現(xiàn)方式的文章就介紹到這了,更多相關(guān)Java動(dòng)態(tài)規(guī)則內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 基于Idea+Jconsole實(shí)現(xiàn)線程監(jiān)控步驟

    基于Idea+Jconsole實(shí)現(xiàn)線程監(jiān)控步驟

    這篇文章主要介紹了基于Idea+Jconsole實(shí)現(xiàn)線程監(jiān)控功能,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-04-04
  • 解決springboot集成rocketmq關(guān)于tag的坑

    解決springboot集成rocketmq關(guān)于tag的坑

    這篇文章主要介紹了解決springboot集成rocketmq關(guān)于tag的坑,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • IntelliJ IDEA 無(wú)法正常使用SVN的問(wèn)題和完美解決辦法

    IntelliJ IDEA 無(wú)法正常使用SVN的問(wèn)題和完美解決辦法

    這篇文章主要介紹了IntelliJ IDEA 無(wú)法正常使用SVN的問(wèn)題和解決辦法,本文給大家分享完美解決方案,通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-08-08
  • MyBatis學(xué)習(xí)教程(五)-實(shí)現(xiàn)關(guān)聯(lián)表查詢方法詳解

    MyBatis學(xué)習(xí)教程(五)-實(shí)現(xiàn)關(guān)聯(lián)表查詢方法詳解

    本文給大家介紹mybatis關(guān)聯(lián)查詢,包括一對(duì)一關(guān)聯(lián)查詢,一對(duì)多關(guān)聯(lián)查詢,代碼簡(jiǎn)單易懂,感興趣的朋友一起學(xué)習(xí)吧
    2016-05-05
  • java實(shí)現(xiàn)字符串轉(zhuǎn)String數(shù)組的方法示例

    java實(shí)現(xiàn)字符串轉(zhuǎn)String數(shù)組的方法示例

    這篇文章主要介紹了java實(shí)現(xiàn)字符串轉(zhuǎn)String數(shù)組的方法,涉及java字符串的遍歷、分割、轉(zhuǎn)換等相關(guān)操作技巧,需要的朋友可以參考下
    2017-10-10
  • SpringBoot整合iText7導(dǎo)出PDF及性能優(yōu)化方式

    SpringBoot整合iText7導(dǎo)出PDF及性能優(yōu)化方式

    在SpringBoot項(xiàng)目中整合iText7庫(kù)以導(dǎo)出PDF文件,不僅能夠滿足報(bào)告生成需求,而且可以處理復(fù)雜的文檔布局與樣式,整合步驟包括添加Maven依賴、編寫PDF生成代碼,性能優(yōu)化方面,建議使用流式處理、緩存樣式與字體、優(yōu)化HTML/CSS結(jié)構(gòu)、采用異步處理
    2024-09-09
  • 寧可用Lombok也不把成員設(shè)置為public原理解析

    寧可用Lombok也不把成員設(shè)置為public原理解析

    這篇文章主要為大家介紹了寧可用Lombok也不把成員設(shè)置為public原理解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • 幾種常見(jiàn)mybatis分頁(yè)的實(shí)現(xiàn)方式

    幾種常見(jiàn)mybatis分頁(yè)的實(shí)現(xiàn)方式

    這篇文章主要介紹了幾種常見(jiàn)mybatis分頁(yè)的實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • SpringBoot實(shí)現(xiàn)自定義Starter的步驟詳解

    SpringBoot實(shí)現(xiàn)自定義Starter的步驟詳解

    在SpringBoot中,Starter是一種特殊的依賴,它可以幫助我們快速地集成一些常用的功能,例如數(shù)據(jù)庫(kù)連接、消息隊(duì)列、Web框架等。在本文中,我們將介紹如何使用Spring Boot實(shí)現(xiàn)自定義Starter,需要的朋友可以參考下
    2023-06-06
  • Java Base64解碼錯(cuò)誤及解決方法

    Java Base64解碼錯(cuò)誤及解決方法

    本篇文章給大家從一個(gè)Java Base64解碼錯(cuò)誤著手給大家分析了錯(cuò)誤的原因以及解決辦法,有興趣的可以參考學(xué)習(xí)下。
    2018-02-02

最新評(píng)論