mvel 调用java_java MVEL2/Spring EL表达式、直接调用、反射性能实测

importjava.io.Serializable;importjava.lang.reflect.Field;importjava.util.HashMap;importjava.util.Map;importorg.mvel2.MVEL;/*** Id 模型*/

public class Id implementsSerializable {privateLong id;publicLong getId() {returnid;

}public voidsetId(Long id) {this.id =id;

}public staticLong get(Id id) {return id == null ? null: id.getId();

}public static voidmain(String[] args) {

Id id= newId();long beg =System.currentTimeMillis();for (long i=0;i<100000;i++) {

id.setId(i);

}

System.out.println(System.currentTimeMillis()-beg);

Map paramMap = new HashMap<>();

String expression= "id.setId(1L);";

paramMap.put("id", id);

beg=System.currentTimeMillis();

Serializable compiled=MVEL.compileExpression(expression);for (long i=0;i<100000;i++) {

MVEL.eval(expression, paramMap);//非编译模式//MVEL.executeExpression(compiled,paramMap);//编译模式

}

System.out.println(System.currentTimeMillis()-beg);

beg=System.currentTimeMillis();try{

Field field= Id.class.getDeclaredField("id");for (long i=0;i<100000;i++) {

field.set(id, i);

}

System.out.println(System.currentTimeMillis()-beg);

}catch (NoSuchFieldException | SecurityException | IllegalArgumentException |IllegalAccessException e) {//TODO Auto-generated catch block

e.printStackTrace();

}

}

}

输出如下:

6  --原生调用

498   --MVEL2表达式

239 -- MVEL2 编译后

18   --反射

还差一个基于Unsafe直接访问的,后面补上。。。。

可见用表达式的性能是非常低下的,即使是编译后。如果真的什么时候需要用表达式的话,可以采用动态编译java类的方式实现。(它可以通过调用javac实现参考https://www.cnblogs.com/anai/p/4269858.html,也可以调用JavaCompiler,参考https://www.cnblogs.com/jxrichar/p/4883465.html)这样可以同时达到原生调用和灵活性的目标。

根据一些文章的性能评测,对于表达式语言,性能最好的是groovy、其次是MVEL,但是我们实际测下来,简单的语句grovvy的性能远不如mvel2。

网上还有一些OGNL & MVEL的性能测试比较(如https://caoyaojun1988-163-com.iteye.com/blog/2089726,还是比较客观的),实际上到现在2019年,我们会发现最终差别就在于有没有采用javac机制,没有采用javac机制的性能就是差一大截,否则不会相差太多,如果某个库说其性能特别NB如Fel,要么就是特定场景高度定制、要么author就是无脑,如果真有这样两全的方案,该方案要么被作为机密、要么被广泛open source了,不需要打广告。PS:我们在原来在一个稽核系统中采用mvel2对数以百万计的数据进行表达式计算,但是实际性能测试下来发现比原生java代码慢了20多倍,开发拒绝接收,最后我们硬是采用了javac的机制实现该特性,性能和原生java基本上相差不到10%。

当然,作为通用的表达式语言,MVEL2在性能要求不是很苛刻的场景中还是推荐使用的http://simpleframework.net/news/view?newsId=028c6068df804c548668b96db31a912b。

https://www.cnblogs.com/keithmo/p/5186693.html

https://www.techug.com/post/dynamic-code-in-java.html

https://blog.csdn.net/sunnyyoona/article/details/75244442

https://yanguz123.iteye.com/blog/2146176

https://www.iteye.com/topic/361794

https://blog.csdn.net/fhm727/article/details/6543152

http://simpleframework.net/news/view?newsId=028c6068df804c548668b96db31a912b

Getting Started for 2.0 MVEL is very easy to use, and just as easy to integrate into your application. Let's take a quick look at a simple MVEL expression: foo.name == "Mr. Foo" This simple expression asks MVEL if the value of foo.name is equal to "Mr. Foo". Simple enough, but what exactly is foo in this case? Well, it can be at least two things: A property of a Context object; or An [External Variable] A context object is something you can use as the base of your expression by which MVEL will attempt to map identifiers to. Consider the following example: public class Person { private String name; public void setName(String name) { this.name = name; } public String getName() { return this.name; } } Lets say we decide to make an instance of this particular class the context object for the expression, and we evaluate it like so: Person personInst = new Person(); personInst.setName("Mr. Foo"); Object result = MVEL.eval("name == 'Mr. Foo'", personInst); When we execute this expression using the eval() method, we will get a result. In this particular case, the value of result will be a Boolean true. The reason for this, is that when the expression name == 'Mr. Foo' is evaluated, MVEL looks at the context object to see if it contain a property/field called name and extracts it. If we wanted to simply extract the value of name from the person instance, we could do that as well: String result = (String) MVEL.eval("name", personInst); assert "Mr. Foo".equals(result); Pretty simple stuff. But what if we want to inject a bunch of variables? MVEL supports that too, and there is both and easy way and a more advanced way (dealing with resolvers – which we won't get to here). The easy way simply involves passing in a Map of variables (names and values), like so: Map vars = new HashMap(); vars.put("x", new Integer(5)); vars.put("y", new Integer(10)); Integer result = (Integer) MVEL.eval("x * y", vars); assert result.intValue() == 50; // Mind the JDK 1.4 compatible code :) Now, so far we've just been looking at using MVEL as a purely interpreted tool. MVEL can also compile expressions to execute them much faster using a different API. Let's convert the last expression into a compiled version: // The compiled expression is serializable and can be cached for re-use. CompiledExpression compiled = MVEL.compileExpression("x * y"); Map vars = new HashMap(); vars.put("x", new Integer(5)); vars.put("y", new Integer(10)); // Executes the compiled expression Integer result = (Integer) MVEL.executeExpression(compiled, vars); assert result.intValue() == 50; Next Steps I hope that wets your appetite. Anyways, you can continue on to the Language Guide and Integration Guide for 2.0's for lots more information. You can also check out the MVEL Shell: an interactive shell.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值