由于Groovy的实现机制,其性能要比Java差很多。因此,很多Groovy项目的做法是对于性能关键点采用Java完成。最近,Cédric Champeau找出了另一种提升应用性能的方法,而且不是借助Java的力量。
该方法的核心思想是对Groovy对象的MetaClass进行改造:
Groovy本质上动态语言。这意味着,在Groovy里,方法的分发是受MetaClass控制的。这种方法的确强大,支持诸如“method missing”或“property missing”这样在很多DSL中都使用的、非常好的小把戏。MetaClass决定了在发起属性或方法调用时预期的行为。
Cédric首先分析了Groovy源码中MetaClassImpl#invokeMethod方法的部分代码,发现:
这段代码大多数时候都是在处理“闭包”相关的问题。
但假若不需要考虑闭包呢?或者POGO里根本就没有闭包呢?于是,他实现了自己的MetaClass:
package groovy.runtime.metaclass.com.mypackage;
public class MySuperFastJavaObjectMetaClass extends MetaClassImpl {
...
@Override
public Object invokeMethod(Class sender, Object object,
String methodName, Object[] originalArguments,
boolean isCallToSuper, boolean fromInsideClass) {
checkInitalised();
if (object == null) {
throw new NullPointerException("Cannot invoke method: " + methodName + " on null object");
}
final Object[] arguments = originalArguments == null ? EMPTY_ARGUMENTS : originalArguments;
MetaMethod method = getMethodWithCaching(sender, methodName, arguments, isCallToSuper);
MetaClassHelper.unwrap(arguments);
if (method != null) {
return method.doMethodInvoke(object, arguments);
} else {
return invokeMissingMethod(object, methodName, arguments);
}
}
}
上面的代码完全摒弃了对于闭包的处理,只是把方法调用直接转发给实际的对象。Cédric指出了值得注意的几点:
- 在包名中使用groovy.runtime.metaclass前缀将保证Groovy自动加载你的metaclass,并把它分配给你的类。
- metaclass的名字是类名+MetaClass后缀。
- 只覆盖那些会导致性能巨大提升的方法。
随后,Cédric又进一步对上述实现进行了优化,相比起来当然就属于细节了,这里就不再叙述。那么这种利用MetaClass缩减方法调用链的效果如何呢?
在增加一个MetaClass之后,在执行时间上我取得了10%的改进。只是增加了这么点MetaClass就取得这样的结果十分令我惊讶,就这个应用来讲,我把执行时间改进了25%。
文后的评论中有人发出疑问:
那为何不用Groovy++呢?它会给你的性能带来同样的好处,我猜还不用这么麻烦。
对此,Cédric回复道:
不用Groovy++有好几个原因。尽管它是一个很有意思的项目,但存在一些缺陷。首先,Alex Tkachman自己也承认它还未为生产环境做好准备(还没到1.0).此外,Groovy和Groovy++的代码在语义上存在区别,这将很难解释/理解。人们已经处理了Java和Groovy之间的区别。向他们解释Groovy和Groovy++的区别将十分复杂。最后,Groovy++要求你要修改代码,尽可能增加显式类型,增加@Typed注解。这对于“代码”来讲可以接受,但DSL无法接受这一点。
同时,他还给出了关于Groovy++讨论的链接。
这是一篇有趣的文章,对于开启我们如何更好的应用Groovy具有非常好的价值。有兴趣的读者,可以访问原文了解代码详情。

最新评论
9 周 6 小时之前
9 周 1 天之前
11 周 5 天之前
11 周 5 天之前
17 周 2 天之前
17 周 4 天之前
19 周 3 天之前
20 周 1 天之前
20 周 2 天之前
20 周 5 天之前