你的Java开发工具包有没有MVEL?

日期: 2011-10-19 作者:TheServerSide.com翻译:张培颖 来源:TechTarget中国 英文

MVEL是什么    MVEL最初是Mike Brock的Valhalla项目的表达计算器。Valhalla本身是一个早期的Seam,就像为自动化“out of the box”web应用而生的框架,虽然Valhalla现在是休眠状态,但是MVEL仍旧作为活跃的开发项目向前发展。通常,我们会将MVEL同OGNL、JEXL、JUEL这样的项目作对比;不论是性能、特性还是易用性,尤其是集成方面,MVEL都已经远远超过那些项目。MVEL还没有尝试另一种JVM语言,但是开始关注解决嵌入式脚本的问题。

   由于内存限制或者沙盒不能用字节码生成的约束环境中,MVEL则十分理……

我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。

我原创,你原创,我们的内容世界才会更加精彩!

【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】

微信公众号

TechTarget微信公众号二维码

TechTarget

官方微博

TechTarget中国官方微博二维码

TechTarget中国

MVEL是什么

   MVEL最初是Mike Brock的Valhalla项目的表达计算器。Valhalla本身是一个早期的Seam,就像为自动化“out of the box”web应用而生的框架,虽然Valhalla现在是休眠状态,但是MVEL仍旧作为活跃的开发项目向前发展。通常,我们会将MVEL同OGNL、JEXL、JUEL这样的项目作对比;不论是性能、特性还是易用性,尤其是集成方面,MVEL都已经远远超过那些项目。MVEL还没有尝试另一种JVM语言,但是开始关注解决嵌入式脚本的问题。

   由于内存限制或者沙盒不能用字节码生成的约束环境中,MVEL则十分理想。取代尝试再创在Java,相反,MVEL目的在于为Java程序员提供一种类似的语法,同时也为短的和简明表达式添加了语法糖衣。

   MVEL是Drools规则引擎的一部分,很多密封集成点式同Drools团队一同开发的。那会其他脚本语言可以再次进行复查,但是也显示了一下的问题:

  • 缺少可选类型安全
  • 集成不良,通常通过映射填入内容。没有字节码不能运作用字节码生成编译时间慢,还增加了可扩展性问题;不用字节码生成运行时执行非常慢
  • 内存消耗过大
  • Jar巨大/依赖规模

  属性访问函数和数据结构

  MVEL支持类javascript语法,这是我们熟悉并喜欢的表达语言,支持简化的属性访问函数,内联映射以及列表:

以下是引用片段:
[1, 2, 3, 4] // array
["key1" : 1, "key2" : 3 ] // map
person.name // simple property accessor
person.pets["rover"].age // map accessor
person.pets["rover"].?age // null safe accessor

  使用“with”声明,并内联函数构造器,下面是等价功能:
 

以下是引用片段:
with ( new Person() ) { 
name = "Bobba Fet", age = "50" 
}
new Person().{ 
name = "Bobba Fet", age = "50" 
}

  也可以对复杂数据结构创建使用内联映射和列表语法:
 

以下是引用片段:
[ people : [ 
new Person().{ name = "Bobba Fet" },
new Person().{ name = "Darth Vader" }
],
places : [ 
new Place().{ name = "Death Star" }
]
]

  在MVEL中就像其他语言一样返回值,默认的是最后一个值。此外,你也可以使用“return”关键词从程序中手动返回。
 

以下是引用片段:
if (val) { “foo”} 
else 
{ “bar”};
Is the same as:
if (val) { return “foo” } 
else 
{ return “bar” };

  这个例子中通过关键词“room”和“doors”返回一个Map,Door参照了两个room Map中以前创建的实例

以下是引用片段:
rooms = [
"basement" : new Room("basement"),
"lounge" : new Room("kitchen")
];
// return is implicit, 
// but can be explicitly added if preferred
doors = [ 
new Door( 
rooms["kitchen"], rooms["basement"] 

];
[ "rooms" : room, "doors" : doors ];

  外部变量词典

  MVEL可以使用Map计算给定的表达,提供一个可用变量词典:

以下是引用片段:
Map vars = new HashMap();
vars.put( "person", p ); 
// p is a previous created instance
//p.pets references a Map.
Dog dog = 
( Dog ) MVEL.eval( "person.pets['rover']", vars );

  上面所说的将会使用MVEL的“interpreted”模式,快速单程编译和执行String。它也能为更快的执行进行预编译。

  MVEL通过性能优化的分析器开发,保持了jar大小,而且意味着MVEL不要求任何附加的外部依赖。Jar大概700kb左右,包括调试信息。编译声明仍旧会被解读,使用一种优化的内部执行图表。对于性能敏感的代码,MVEL的优化程序可以发出字节码来加速域和方法的访问。

  编译例子:

以下是引用片段:
ExecutableStatement stmt = 
MVEL.compileExpression( "person.pets['rover']" );
MVEL.executeExpression( stmt, vars );

  内容对象可用来执行脚本,而不是提供对象。注意下面的例子中,我们可以直接访问“pet的属性”,这对于Person的方法也同样有效:

以下是引用片段:
Dog dog = 
( Dog ) MVEL.eval( "pets['rover']", p );

  内容对象和变量词典可以共同使用:

以下是引用片段:
vars.put( "otherPet", patch ) 
// patch is another pet
MVEL.eval( 
"pets['rover'].age == otherPet.age", p, vars 
);

  输入声明可行,“*”也可以成套引进使用:

以下是引用片段:
"import org.domain.Dog; pets['rover'] == new Dog('patch', 7)"

  类输入可以通过可重用的ParserConfiguration自动添加,如果这个输入可以被编译中的大多数表达所共享,ParserConfiguration相当不错。
 

以下是引用片段:
ParserConfiguration pconf = 
 new ParserConfiguration();
pconf.addImport( "Dog", Dog.class );
ParserContext pctx = new ParserContext( pconf );
MVEL.compileExpression( 
 "pets['rover'] == new Dog('patch', 7)", pctx 
);

  输入信息和输入安全

  ParserContext在外部变量编译时间可随意用于提供输入信息。在哪里提供输入信息,编译器就可以更好的假设,结果就是更快地执行性能。局部变量部署支持类型推断,如果他们可以推断出类型就可以优化。
 

以下是引用片段:
ParserContext pctx = new ParserContext( );
pctx.addInput( “p”, Person.class );
MVEL.compileExpression( "p.pets['rover']", pctx );

  此外,MVEL已经能够以非类型安全的方式动态执行,这一点类似其他的表达语言,像OGNL或者JEXL。但是编译要确保所有输入安全,使用可选的强键入。如果输入信息不可用或者不能推断,编译就会失败。
 
以下是引用片段:
ParserContext pctx = ParserContext.create()
.stronglyTyped()
.withInput(“p”, Person.class);
MVEL.compileExpression( "p.pets['rover']", pctx );
 
Setting the type of the context object can be done via the 'this' input:
 
ParserContext pctx = ParserContext.create()
.stronglyTyped()
.withInput( “this”, Person.class );
MVEL.compileExpression( "this.toString()", pctx );

  完全的输入推断是为局部变量提供的,所以输入声明或者类型转换的支持是可选的。MVEL也可以从可用的泛型中推断输入信息:
 

以下是引用片段:
public static class Person {
private Map<String, Pet> pets;
...
}
...
 
ParserContext pctx = ParserContext.create()
.stronglyTyped();
.withInput( “person”, Person.class );
//Both the following MVEL statements are valid and type safe:
MVEL.compileExpression( "Pet rover = (Pet) person[“rover”];n”+
“return rover.age;", pctx );
MVEL.compileExpression( "rover = person[“rover”];n”+
“return rover.age;", pctx );

  MVEL比较有意思的一项性能是提供分析表达式的功能,而且可以告诉你外部输入,也就是变量不是本地分配的。也可以用于为局部变量报告推断输入。确定了外部输入时,强键入就不能使用,而且输入的内容将会被作为java.lang.Object处理。
 

以下是引用片段:
ParserContext pctx = ParserContext.create();
MVEL.compileExpression( "person.pets['rover']", pctx );
// Map returns [“person” : Object.class]
Map<String, Class> inputs = pctx.getInputs();

  从局部变量获取输入:
 
以下是引用片段:
ParserContext pctx = ParserContext.create()
.stronglyTyped()
.withInput( “person”, Person.class );
MVEL.compileExpression( "pet = person.pets['rover']", pctx );
// Map returns [“pet” : Pet.class]
Map<String, Class> inputs = pctx.getVariables();

  索引变量词典

  对外部变量词典使用Map是嵌入式脚本语言最常用的方式,但是并不是性能的最优化方式。这回消耗过多的内存,而且每一次读或者写就是一个Map put/get。MVEL的最新版本通过配置属性“indexAllocation”,引入了预计算索引变量,所以读和写变量和访问矩阵一样快速,在内存消耗上不会比矩阵匹配的变量长度需求多。索引也可以用于局部变量,确保高性能。
 

以下是引用片段:
ParserContext pctx = new ParserContext( )
.stronglyTyped()
.withInput(“person”, Person.class)
.withInput(“otherPet”, Person.class)
 
String[] varNames = new String[] { “person”, “otherPet” };
 
pctx.addIndexedInput(varNames);
pctx.setIndexAllocation(true);
 
String exp = “person.pets['rover'].age == otherPet.age”;
 
SharedVariableSpaceModel model = 
VariableSpaceCompiler.compileShared(expr, ctx);
 
ExecutableStatement stmt = MVEL.compileExpression( expr, pctx );
// Notice the values order must 
// match the indexedInput variable name order
Object[] values = new Object[] { person, patch };
 
MVEL.executeExpression(stmt, model.createFactory(values) );

  增强功能

  • 可选字节码生成
  • 高度优化实时编译器
  • 编写优化
  • 逃逸分析和冗余优化

  总结

  到现在你应该可以确信,作为Java开发者你不能把MVEL拿出你的工具盒了吧,MVEL填补了完成编程环境之间独特的代沟,像GroovyScala和表达语言OGNLJUEL。就算全世界在讨论Gavin King的Ceylon项目的各种优点,他们错过了Jboss的秘密武器。

翻译

张培颖
张培颖

云计算网站编辑

相关推荐

  • 为什么开源企业的开源大旗正在褪色

    最近这几年,开源一直是人们比较关注的话题,不过现在也该到冷静下来进行思考的时候了,真正的开源公司已经利用开源赚得盆满钵盈。

  • 新Java Web应用工具与基本工具的比较

    在评估工具和框架的时候,很重要的一点是理解它们是如何支撑你的团队正在开发的特定应用的。为手上的任务使用设计得当的工具应当始终成为首要关注点。

  • 优化Jboss EAP平台的12项最佳实践

    在过去几年里,NBC环球电影公司的Web架构团队牺牲了可观的时间和资源去改善其高度分布的企业架构。Richir Choudhry、Alpesh Vaghela……

  • 开源PaaS技术手册

    开源业界向来不太平,关于诸多技术的开源未来足以让很多粉丝兴奋躁动起来。商业软件开始揉进开源技术,开源技术也成为IT大佬们得基础架构,这一种趋势蔓延的缓慢有有力。在广告漫天飞得云计算中,开源的分量有多重?是否走向云端就意味着走向开源?开源的PaaS如何选择?如何为开源项目选择PaaS厂商?哪些服务平台值得我们关注,下面我们一一来揭晓。