- 浏览: 3015127 次
- 性别:
- 来自: 海外
文章分类
- 全部博客 (430)
- Programming Languages (23)
- Compiler (20)
- Virtual Machine (57)
- Garbage Collection (4)
- HotSpot VM (26)
- Mono (2)
- SSCLI Rotor (1)
- Harmony (0)
- DLR (19)
- Ruby (28)
- C# (38)
- F# (3)
- Haskell (0)
- Scheme (1)
- Regular Expression (5)
- Python (4)
- ECMAScript (2)
- JavaScript (18)
- ActionScript (7)
- Squirrel (2)
- C (6)
- C++ (10)
- D (2)
- .NET (13)
- Java (86)
- Scala (1)
- Groovy (3)
- Optimization (6)
- Data Structure and Algorithm (3)
- Books (4)
- WPF (1)
- Game Engines (7)
- 吉里吉里 (12)
- UML (1)
- Reverse Engineering (11)
- NSIS (4)
- Utilities (3)
- Design Patterns (1)
- Visual Studio (9)
- Windows 7 (3)
- x86 Assembler (1)
- Android (2)
- School Assignment / Test (6)
- Anti-virus (1)
- REST (1)
- Profiling (1)
- misc (39)
- NetOA (12)
- rant (6)
- anime (5)
- Links (12)
- CLR (7)
- GC (1)
- OpenJDK (2)
- JVM (4)
- KVM (0)
- Rhino (1)
- LINQ (2)
- JScript (0)
- Nashorn (0)
- Dalvik (1)
- DTrace (0)
- LLVM (0)
- MSIL (0)
最新评论
-
mldxs:
虽然很多还是看不懂,写的很好!
虚拟机随谈(一):解释器,树遍历解释器,基于栈与基于寄存器,大杂烩 -
HanyuKing:
Java的多维数组 -
funnyone:
Java 8的default method与method resolution -
ljs_nogard:
Xamarin workbook - .Net Core 中不 ...
LINQ的恶搞…… -
txm119161336:
allocatestlye1 顺序为 // Fields o ...
最近做的两次Java/JVM分享的概要
最近在项目里要在Java中整合Groovy脚本来粘合各个组件/服务,所以这两天在测试几种整合方法。最初是想用JSR 223系的API,不过我们这边对ClassLoader有特别需求,JSR 223的API满足不了,所以还是转而考虑Groovy自身的整合机制。
除了BSF与JSR 223之外,整合Groovy基本上有三种途径:GroovyShell(以及Eval)、GroovyClassLoader和GroovyScriptEngine。这些在官网的Embedding Groovy文档上有所描述,在几本Groovy的书里也有提及。
然而在整合Groovy脚本的时候可能会遇到一类陷阱:临时加载的类未能及时被释放,进而导致PermGen OutOfMemoryError;没那么严重的时候也会引发比较频繁的full GC从而影响稳定运行时的性能。
如果只是要执行一些Groovy脚本,那么GroovyShell看来是个不错的选择。于是用它做个小测试:
(环境在后面的截图里有写,这里就不详细说了。Windows XP SP3/Sun JDK 1.6.0u18/client默认参数/Groovy 1.7.1)
启动这个程序,按一下回车,放着跑不到一分钟就会看到异常:
如果在启动这个测试时加上-verbose选项,可以看到每次执行GroovyShell.parse()方法时都会打印出这样的日志:
也就是说上面测试中的脚本每次被parse()都新生成两个类,一个对应顶层代码,一个对应其中的mul()方法。在循环中调用parse()方法,不消一会儿就把HotSpot的PermGen给撑爆了;虽然执行过程中也可以看到PermGen的空间紧张经常引发full GC,而在full GC时会卸载掉许多不再有引用的类,但这个测试中卸载的速度没有生成的速度快,就杯具了。
除了类自身之外,类中的常量池所引用的字符串也都需要被intern,上面的例子中像"mul"这个名字就会被intern掉;在HotSpot中,intern的String实例也是在PermGen上分配空间的。内容相同的字符串就算被intern很多次在PermGen的字符串池里也只会有一份,不过如果连续执行很多脚本,脚本里在“成员”和“类型”级别上出现了很多不同的标识符的话,这也会对字符串池造成压力。
用JConsole可以形象的看到PermGen爆掉的过程。下面两张截图中右边骤然下降的线是在测试程序抛出异常而终止后JConsole与之连接被断开的时候的,可以忽略掉。
(补一张PermGen趋势截图)
==========================================================================
Sun JDK 1.6.0u18的HotSpot在32位Windows XP SP3上默认选用client模式,默认PermGen大小是64MB。如果在上面的测试里给入参数-XX:MaxPermSize=512m,将PermGen最大大小设置到512MB,情况会怎样呢?放着让它多跑几分钟,会看到:
如果看JConsole监视到的类加载状况,会看到:
右边陡然下降的曲线跟上一个测试一样是在抛了异常之后的部分,可以忽略。
中间一段看起来很平,看来是没问题?
其实不然。如果结合程序的执行速度与GC消耗的时间来看,会发现加载类的数量的曲线比较平的这段时间里,上面测试代码的每轮循环都要等很久才会输出一个35,而大部分时间都消耗在了full GC上;这是由于“某种原因”(*)使得GC堆的年老代非常满,于是稍微分配一点空间就要触发full GC。最终GC堆还是没撑住,就爆了。
也就是说这次没有让PermGen爆掉只不过是因为瓶颈转移到别的部分了而已。
*:这个“某种原因”以后或许会发篇帖分析一下。这篇就只谈谈现象吧。
==========================================================================
GroovyShell上的几个方法都有同样的问题,像是evaluate()的各个重载、parse(),还有Eval.me()/x/xy()/xyz()这些方法都一样。
当然,在上面的测试中只要把shell.parse(scriptText);这句移到循环的外面就可以避免撑爆PermGen的问题——因为只调用了一次parse()方法,相应的也就只生成了对应的那些新的类。
于是这里就有个启示:如果嵌入GroovyShell的场景需要经常执行Groovy脚本,那么或许应该通过weak cache来检查先前是不是已经处理过当前输入的脚本,没处理过的时候才去调用GroovyShell.parse()并将脚本记录到weak cache里。
==========================================================================
如果GroovyShell可能导致PermGen问题,那GroovyClassLoader是不是也一样会呢?换用下面的代码来测试的话:
却发现它跑起来没导致PermGen OOM。
同样看看JConsole监控的截图:
可以看到虽然被加载的类仍然非常多,但多数都及时被卸载了所以PermGen能动态维持在一个不太满的水平上。
观察-verbose得到的日志,可以看到上面例子中每次调用GroovyClassLoader.parseClass()只生成并加载了一个类:
虽然每次生成并加载的类的数量比GroovyShell.parse()的少,但这个测试总觉得缺了点什么。对,没对那些新生成的类生成过实例。那么改一下,加上对Class.newInstance()的调用:
则类加载与PermGen的表现又有所不同了:
虽然还是没有因为PermGen而OOM,但PermGen的压力明显比不调用newInstance()时高了些。
接下来,模仿我们这边已有的一个项目里对Groovy的用法,加上对新生成的实例的方法调用再来测试一下:
结果也还正常,跑了十几分钟都没有OOM,也没有表现出OOM的倾向。Good。
==========================================================================
说来GroovyShell里还特别写了注释说不缓存脚本:
不乱缓存东西或许也算是一种美德吧……?
GroovyShell.parse()内部其实也就是调用GroovyClassLoader.parseClass()去解析Groovy脚本并生成Class实例(会是groovy.lang.Script的子类),然后调用Class.newInstance()构造出一个新的实例以Script类型的引用返回出来。
既然它默认不缓存东西,怎么上面的例子里用它就会PermGen OOM而直接用GroovyClassLoader就没事呢?看来是两个例子中脚本的内容不同带来了差异。不过换成下面的版本来测却并没出问题:
用GroovyShell的时候什么地方挂住了什么不该挂住的引用么……?
下次再找原因吧……
我也没啥现成的好办法。用JDI来写一个是能做到的但是好麻烦啊(远目
耶,期待一下~~
除了BSF与JSR 223之外,整合Groovy基本上有三种途径:GroovyShell(以及Eval)、GroovyClassLoader和GroovyScriptEngine。这些在官网的Embedding Groovy文档上有所描述,在几本Groovy的书里也有提及。
然而在整合Groovy脚本的时候可能会遇到一类陷阱:临时加载的类未能及时被释放,进而导致PermGen OutOfMemoryError;没那么严重的时候也会引发比较频繁的full GC从而影响稳定运行时的性能。
如果只是要执行一些Groovy脚本,那么GroovyShell看来是个不错的选择。于是用它做个小测试:
(环境在后面的截图里有写,这里就不详细说了。Windows XP SP3/Sun JDK 1.6.0u18/client默认参数/Groovy 1.7.1)
package fx.test; import groovy.lang.GroovyShell; import groovy.lang.Script; import java.io.IOException; /** * @author sajia * */ public class TestGroovyShell { // see if the number of loaded class keeps growing when // using GroovyShell.parse public static void test() { GroovyShell shell = new GroovyShell(); String scriptText = "def mul(x, y) { x * y }\nprintln mul(5, 7)"; while (true) { Script script = shell.parse(scriptText); Object result = script.run(); } } public static void main(String[] args) { try { System.in.read(); } catch (IOException e) { e.printStackTrace(); } test(); } }
启动这个程序,按一下回车,放着跑不到一分钟就会看到异常:
Exception in thread "main" java.lang.OutOfMemoryError: PermGen space at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:616) at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:124) at groovy.lang.GroovyClassLoader.access$300(GroovyClassLoader.java:55) at groovy.lang.GroovyClassLoader$ClassCollector.createClass(GroovyClassLoader.java:496) at groovy.lang.GroovyClassLoader$ClassCollector.onClassNode(GroovyClassLoader.java:513) at groovy.lang.GroovyClassLoader$ClassCollector.call(GroovyClassLoader.java:517) at org.codehaus.groovy.control.CompilationUnit$11.call(CompilationUnit.java:767) at org.codehaus.groovy.control.CompilationUnit.applyToPrimaryClassNodes(CompilationUnit.java:971) at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:519) at org.codehaus.groovy.control.CompilationUnit.processPhaseOperations(CompilationUnit.java:497) at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:474) at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:292) at groovy.lang.GroovyShell.parseClass(GroovyShell.java:727) at groovy.lang.GroovyShell.parse(GroovyShell.java:739) at groovy.lang.GroovyShell.parse(GroovyShell.java:766) at groovy.lang.GroovyShell.parse(GroovyShell.java:757) at fx.test.TestGroovyShell.test(TestGroovyShell.java:20) at fx.test.TestGroovyShell.main(TestGroovyShell.java:31)
如果在启动这个测试时加上-verbose选项,可以看到每次执行GroovyShell.parse()方法时都会打印出这样的日志:
[Loaded Script183 from file:/groovy/shell] [Loaded Script183$mul from file:/groovy/shell]
也就是说上面测试中的脚本每次被parse()都新生成两个类,一个对应顶层代码,一个对应其中的mul()方法。在循环中调用parse()方法,不消一会儿就把HotSpot的PermGen给撑爆了;虽然执行过程中也可以看到PermGen的空间紧张经常引发full GC,而在full GC时会卸载掉许多不再有引用的类,但这个测试中卸载的速度没有生成的速度快,就杯具了。
除了类自身之外,类中的常量池所引用的字符串也都需要被intern,上面的例子中像"mul"这个名字就会被intern掉;在HotSpot中,intern的String实例也是在PermGen上分配空间的。内容相同的字符串就算被intern很多次在PermGen的字符串池里也只会有一份,不过如果连续执行很多脚本,脚本里在“成员”和“类型”级别上出现了很多不同的标识符的话,这也会对字符串池造成压力。
用JConsole可以形象的看到PermGen爆掉的过程。下面两张截图中右边骤然下降的线是在测试程序抛出异常而终止后JConsole与之连接被断开的时候的,可以忽略掉。
(补一张PermGen趋势截图)
==========================================================================
Sun JDK 1.6.0u18的HotSpot在32位Windows XP SP3上默认选用client模式,默认PermGen大小是64MB。如果在上面的测试里给入参数-XX:MaxPermSize=512m,将PermGen最大大小设置到512MB,情况会怎样呢?放着让它多跑几分钟,会看到:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at java.util.Arrays.copyOfRange(Unknown Source) at java.lang.String.<init>(Unknown Source) at java.lang.StringBuffer.toString(Unknown Source) at java.net.URLStreamHandler.toExternalForm(Unknown Source) at java.net.URL.toExternalForm(Unknown Source) at java.net.URL.toString(Unknown Source) at java.lang.ClassLoader.defineClassSourceLocation(Unknown Source) at java.lang.ClassLoader.defineClass(Unknown Source) at org.codehaus.groovy.reflection.ClassLoaderForClassArtifacts.define(ClassLoaderForClassArtifacts.java:27) at org.codehaus.groovy.reflection.ClassLoaderForClassArtifacts$1.run(ClassLoaderForClassArtifacts.java:71) at org.codehaus.groovy.reflection.ClassLoaderForClassArtifacts$1.run(ClassLoaderForClassArtifacts.java:69) at java.security.AccessController.doPrivileged(Native Method) at org.codehaus.groovy.reflection.ClassLoaderForClassArtifacts.defineClassAndGetConstructor(ClassLoaderForClassArtifacts.java:69) at org.codehaus.groovy.runtime.callsite.CallSiteGenerator.compilePojoMethod(CallSiteGenerator.java:227) at org.codehaus.groovy.reflection.CachedMethod.createPojoMetaMethodSite(CachedMethod.java:244) at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.createCachedMethodSite(PojoMetaMethodSite.java:158) at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.createPojoMetaMethodSite(PojoMetaMethodSite.java:147) at groovy.lang.MetaClassImpl.createPojoCallSite(MetaClassImpl.java:2994) at org.codehaus.groovy.runtime.callsite.CallSiteArray.createPojoSite(CallSiteArray.java:114) at org.codehaus.groovy.runtime.callsite.CallSiteArray.createCallSite(CallSiteArray.java:148) at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:40) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:117) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125) at org.codehaus.groovy.ast.builder.AstBuilderInvocationTrap.visitMethodCallExpression(AstBuilderTransformation.groovy:179) at org.codehaus.groovy.ast.expr.MethodCallExpression.visit(MethodCallExpression.java:67) at org.codehaus.groovy.ast.CodeVisitorSupport.visitExpressionStatement(CodeVisitorSupport.java:69) at org.codehaus.groovy.ast.stmt.ExpressionStatement.visit(ExpressionStatement.java:40) at org.codehaus.groovy.ast.CodeVisitorSupport.visitBlockStatement(CodeVisitorSupport.java:35) at org.codehaus.groovy.ast.stmt.BlockStatement.visit(BlockStatement.java:51) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
如果看JConsole监视到的类加载状况,会看到:
右边陡然下降的曲线跟上一个测试一样是在抛了异常之后的部分,可以忽略。
中间一段看起来很平,看来是没问题?
其实不然。如果结合程序的执行速度与GC消耗的时间来看,会发现加载类的数量的曲线比较平的这段时间里,上面测试代码的每轮循环都要等很久才会输出一个35,而大部分时间都消耗在了full GC上;这是由于“某种原因”(*)使得GC堆的年老代非常满,于是稍微分配一点空间就要触发full GC。最终GC堆还是没撑住,就爆了。
也就是说这次没有让PermGen爆掉只不过是因为瓶颈转移到别的部分了而已。
*:这个“某种原因”以后或许会发篇帖分析一下。这篇就只谈谈现象吧。
==========================================================================
GroovyShell上的几个方法都有同样的问题,像是evaluate()的各个重载、parse(),还有Eval.me()/x/xy()/xyz()这些方法都一样。
当然,在上面的测试中只要把shell.parse(scriptText);这句移到循环的外面就可以避免撑爆PermGen的问题——因为只调用了一次parse()方法,相应的也就只生成了对应的那些新的类。
于是这里就有个启示:如果嵌入GroovyShell的场景需要经常执行Groovy脚本,那么或许应该通过weak cache来检查先前是不是已经处理过当前输入的脚本,没处理过的时候才去调用GroovyShell.parse()并将脚本记录到weak cache里。
==========================================================================
如果GroovyShell可能导致PermGen问题,那GroovyClassLoader是不是也一样会呢?换用下面的代码来测试的话:
package fx.test; import groovy.lang.GroovyClassLoader; import java.io.IOException; /** * @author sajia * */ public class TestGroovyClassLoader { // see if the number of loaded class keeps growing when // using GroovyClassLoader.parseClass public static void test() { GroovyClassLoader loader = new GroovyClassLoader(); String scriptText = "class Foo {\n" + " int add(int x, int y) { x + y }\n" + "}"; Class<?> clazz = null; while (true) { Class<?> newClazz = loader.parseClass(scriptText); if (clazz == newClazz) { System.out.println("class cached"); break; } clazz = newClazz; } } public static void main(String[] args) { try { System.in.read(); } catch (IOException e) { e.printStackTrace(); } test(); } }
却发现它跑起来没导致PermGen OOM。
同样看看JConsole监控的截图:
可以看到虽然被加载的类仍然非常多,但多数都及时被卸载了所以PermGen能动态维持在一个不太满的水平上。
观察-verbose得到的日志,可以看到上面例子中每次调用GroovyClassLoader.parseClass()只生成并加载了一个类:
[Loaded Foo from file:/groovy/script]
虽然每次生成并加载的类的数量比GroovyShell.parse()的少,但这个测试总觉得缺了点什么。对,没对那些新生成的类生成过实例。那么改一下,加上对Class.newInstance()的调用:
Class<?> clazz = null; while (true) { Class<?> newClazz = loader.parseClass(scriptText); try { newClazz.newInstance(); // make new instance! } catch (Exception e) { e.printStackTrace(); } if (clazz == newClazz) { System.out.println("class cached"); break; } clazz = newClazz; }
则类加载与PermGen的表现又有所不同了:
虽然还是没有因为PermGen而OOM,但PermGen的压力明显比不调用newInstance()时高了些。
接下来,模仿我们这边已有的一个项目里对Groovy的用法,加上对新生成的实例的方法调用再来测试一下:
public static void test() { String scriptText = "class Foo {\n" + " int add(int x, int y) { x + y }\n" + "}"; Class<?> clazz = null; while (true) { GroovyClassLoader loader = new GroovyClassLoader(); Class<?> newClazz = loader.parseClass(scriptText); try { Object obj = newClazz.newInstance(); Object i = obj.getClass() .getMethod("add", int.class, int.class) .invoke(obj, 2, 3); } catch (Exception e) { e.printStackTrace(); } if (clazz == newClazz) { System.out.println("class cached"); break; } clazz = newClazz; } }
结果也还正常,跑了十几分钟都没有OOM,也没有表现出OOM的倾向。Good。
==========================================================================
说来GroovyShell里还特别写了注释说不缓存脚本:
private Class parseClass(final GroovyCodeSource codeSource) throws CompilationFailedException { // Don't cache scripts return loader.parseClass(codeSource, false); }
不乱缓存东西或许也算是一种美德吧……?
GroovyShell.parse()内部其实也就是调用GroovyClassLoader.parseClass()去解析Groovy脚本并生成Class实例(会是groovy.lang.Script的子类),然后调用Class.newInstance()构造出一个新的实例以Script类型的引用返回出来。
既然它默认不缓存东西,怎么上面的例子里用它就会PermGen OOM而直接用GroovyClassLoader就没事呢?看来是两个例子中脚本的内容不同带来了差异。不过换成下面的版本来测却并没出问题:
package fx.test; import groovy.lang.GroovyClassLoader; import groovy.lang.Script; import java.io.IOException; /** * @author sajia * */ public class TestGroovyClassLoader { // see if the number of loaded class keeps growing when // using GroovyClassLoader.parseClass public static void test() { String scriptText = "def mul(x, y) { x * y }\nprintln mul(5, 7)"; while (true) { GroovyClassLoader loader = new GroovyClassLoader(); Class<?> newClazz = loader.parseClass(scriptText); try { Object obj = newClazz.newInstance(); Script script = (Script) obj; script.run(); } catch (Exception e) { e.printStackTrace(); } } } public static void main(String[] args) { try { System.in.read(); } catch (IOException e) { e.printStackTrace(); } test(); } }
用GroovyShell的时候什么地方挂住了什么不该挂住的引用么……?
下次再找原因吧……
评论
10 楼
LinApex
2014-04-12
good,一直对 groovy 性能这块有担忧,帮我解决了一点疑问
9 楼
bo_hai
2013-05-06
8 楼
beneo
2013-01-06
不过有个#resetLoadedClasses这个函数
7 楼
beneo
2013-01-06
我错了,还是有这个情况,GroovyShell
6 楼
beneo
2013-01-06
2.0.5 groovy-all
测试 GroovyShell 不会有 OOM 了
测试 GroovyShell 不会有 OOM 了
5 楼
我改名了
2012-09-28
写的不错,支持 。
4 楼
RednaxelaFX
2011-12-29
scholers 写道
请问下有没有好的方法调试脚本的内容?
就是你文中提到的groovyclassloader加载进去的脚本
就是你文中提到的groovyclassloader加载进去的脚本
我也没啥现成的好办法。用JDI来写一个是能做到的但是好麻烦啊(远目
3 楼
scholers
2011-12-29
请问下有没有好的方法调试脚本的内容?
就是你文中提到的groovyclassloader加载进去的脚本
就是你文中提到的groovyclassloader加载进去的脚本
2 楼
RednaxelaFX
2010-03-20
JohnnyJian 写道
我刚好准备下一篇博客写关于GroovyClassLoader的内容
耶,期待一下~~
1 楼
JohnnyJian
2010-03-20
我刚好准备下一篇博客写关于GroovyClassLoader的内容
发表评论
-
Groovy 1.8的find的closure不被GC?
2011-07-15 16:51 0焦义 (15:58:35): groovy 的 find 创 ... -
嵌入Groovy脚本时添加一些默认import
2011-01-23 17:32 4959刚才给在做的项目里加了些便捷功能,把做法记下来。 我们在Jav ... -
通过Java/JMX得到full GC次数?
2010-10-20 23:40 15009今天有个同事问如何能通过JMX获取到某个Java进程的full ... -
各种Groovy小技巧收集
2010-03-26 18:32 0根据一个Map指定一个对象的属性值: groovy:000&g ... -
Groovy里各种小陷阱收集
2010-03-21 20:50 0class Foo { String value ...
相关推荐
Java调用Groovy,实时动态加载数据库groovy脚本,java读取mongoDB的groovy脚本,加载实时运行,热部署
干货:Jenkins Pipeline调用shell、python、java、groovy脚本的正确使用姿势.doc
java 动态脚本语言 精通 Groovy
groovy脚本实现对数据库的增删改查,groovy脚本不需要编译,十分实用
Java中使用Groovy的三种方式,详细见我的博客。
Groovy 调用 Java 类groovy 调用 Java class 十分方便,只需要在类前导入该 Java 类,在 Groovy 代码中就可以无缝使用该
脚本通过上下文applicationcontext获取被测试应用bean,从而可以进行接口内容获取等操作。目前该方式主要运用到性能平台脚本搭建、代码深度测试、接口测试、白盒测试等多方面。...支持Java、groovy脚本。
1、eclipse安装groovy的插件。 2、创建java project。 3、把groovy-all-2.1.9.jar,加入...4、编写hello.groovy脚本文件,并在java代码中调用脚本文件 http://blog.csdn.net/bolg_hero/article/details/19077981
Android Studio中的Gradle开发脚本语言Groovy,Groovy入门,以及精通
Making Java Groovy is a practical handbook for developers who want to blend Groovy into their day to day work with Java It starts by introducing the key differences between Java and Groovy and how you...
项目从es2升级到es6,groovy脚本也要相应的转换为painless脚本,转换过程中遇到了很多坑,特此总结成文档,供大家一起交流学习。
概述主要介绍Java、spring与groovy结合使用,高清英文版本
Making Java Groovy
执行测试开发过程中的groovy脚本,无须安装,解压即可使用,直接运行bin目录下的groovyConsole.bat即可。
groovy脚本语言bin groovy-binary-1.6.5.zip
gstorm, 在groovy脚本中,一个用于数据库和CSV文件的简单 ORM GStorm - Groovy单个表 ORMGStorm是一个轻量级的持久性 helper,允许你在没有任何样板代码的情况下持久化数据。 它也可以充当CSV文件的和 ORM 。示例...
动态加载指定目录下的groovy脚本,并将其注册为groovy bean,放置于ApplicationContext容器中,并使用命名空间进行分类区分(一个namespace对应于一个ApplicationContext)。同时能够动态感知到groovy脚本的新增、修改...
动态加载指定目录下的groovy脚本,并将其注册为groovy bean,放置于ApplicationContext容器中,并使用命名空间进行分类区分(一个namespace对应于一个ApplicationContext)。同时能够动态感知到groovy脚本的新增、修改...
脚本解析工具,可使用Groovy或Xquery解析JSON报文或XML报文
Groovy环境搭建教程中的例子工程,纯Java、纯Groovy以及Java+Groovy混合 教程参考:http://blog.csdn.net/rcom10002/archive/2011/06/26/6568557.aspx