- 浏览: 3053347 次
- 性别:
- 来自: 海外
文章分类
- 全部博客 (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 5031刚才给在做的项目里加了些便捷功能,把做法记下来。 我们在Jav ... -
通过Java/JMX得到full GC次数?
2010-10-20 23:40 15083今天有个同事问如何能通过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脚本,Java整合Groovy脚本Java整合Groovy脚本,Java整合Groovy脚本Java整合Groovy脚本,Java整合Groovy脚本Java整合Groovy脚本,Java整合Groovy脚本Java整合Groovy脚本,Java整合Groovy脚本Java整合...
我们可以编写一个Java方法,从MongoDB中查询到Groovy脚本,然后利用上述的Groovy调用机制执行这些脚本。 例如,我们可能会有一个MongoDB集合,其中每个文档包含一个字段存储Groovy脚本。Java代码会连接到MongoDB,...
例如在服务器上执行 shell 命令、运行 python 或者 java 测试代码以及使用 groovy 脚本来实现一些更为复杂的功能等等。 执行 shell 命令 在 Jenkins Pipeline 中,使用 `sh` 指令可以执行 shell 命令。例如,使用 ...
在调用Dubbo接口方面,Dubbo是一个高性能、轻量级的Java RPC框架。Groovy脚本可以通过Java API直接调用Dubbo服务,就像在Java代码中一样。首先,你需要在脚本中导入Dubbo的相关依赖,然后创建Dubbo的消费者...
Groovy是一种基于Java平台的动态脚本语言,它在Java开发者中越来越受欢迎,因为它提供了简洁、灵活的语法,以及强大的动态编程能力。Groovy与Java兼容性极佳,可以直接调用Java类库,使得它在Java生态系统中具有广泛...
标题中的“Groovy和Java相互调用1”指的是在编程时如何在Groovy语言环境中调用Java类,以及反之,如何在Java程序中调用Groovy类。这是一种跨语言交互的方式,特别是在混合使用Groovy和Java的项目中非常常见。 ...
在Java开发中,Groovy是一种强大的、动态类型的脚本语言,它可以无缝地与Java代码集成,为开发者提供了更简洁、灵活的语法。本文将深入探讨在Java项目中使用Groovy的三种主要方式,并阐述它们各自的优势和应用场景。...
Groovy是一种运行在Java平台上的动态脚本语言,它与Java紧密集成,提供了一种简洁、灵活的方式来编写Java代码。Groovy不仅支持静态类型检查,还可以在运行时动态地编译和执行代码,这使得它在Java平台中的应用场景...
总的来说,这个“groovy脚本执行工具”是一个对于Java开发者非常有用的工具,它简化了Groovy脚本的执行流程,便于在日常开发和测试中快速使用Groovy。无论你是新手还是经验丰富的开发者,都可以利用这个工具快速上手...
在实际项目中,Groovy还常与其他工具结合,如Grails(一个基于Groovy的Web框架),或者Gradle(构建自动化工具)。这些工具也支持Groovy脚本,使数据库操作更加灵活和高效。总的来说,掌握Groovy进行数据库操作是...
在自动化测试领域,Groovy脚本以其在Java平台上的卓越性能和灵活性,成为了开发者的热门选择。Groovy是一种基于JVM的动态编程语言,它不仅继承了Java的强大功能,还引入了动态类型、闭包、DSL等现代编程特性,使得...
标题“hugo110-java_run_groovy-master_java_”表明这是一个关于使用Java运行Groovy脚本的项目,可能是某个GitHub仓库的克隆或归档。描述中提到,这个环境是为了方便用户(可能是开发者)实践Groovy语言,并为后续的...
- 获取 ScriptEngine 实例:通过 ScriptEngineManager 获取一个脚本引擎 ScriptEngine 对象。 - 执行脚本:使用 ScriptEngine 的 eval 方法执行Groovy脚本。 - javax.script 包结构:javax.script 包中定义了脚本...
这里创建了一个 `list` 变量,并在 Groovy 脚本中定义了一个方法 `call()`,然后通过 `evaluate` 调用这个方法。 如果你的 Groovy 脚本是一个完整的类结构,包括 `main` 方法,你可以使用 `GroovyShell` 来执行 `...
Jython是Python的一个Java实现,它允许Java开发者利用Python的强大语法和丰富的库。要使用Jython,首先需要在项目中引入Jython的jar包。然后,你可以通过`ScriptEngineManager`和`ScriptEngine`接口来执行Jython脚本...
脚本通过上下文applicationcontext获取被测试应用bean,从而可以进行接口内容获取等操作。目前该方式主要运用到性能平台脚本搭建、代码深度测试、接口测试、白盒测试等多方面。...支持Java、groovy脚本。
总之,Groovy脚本语言bin提供的1.6.5版本是一个全面的开发包,旨在支持开发人员在JVM上快速开发、测试和部署Groovy应用程序。无论是对于新手还是有经验的Java开发者,Groovy都提供了一种强大而灵活的工具,以提升...
1. **SpringBoot**: SpringBoot是Spring框架的一个模块,旨在简化Spring应用的初始搭建以及开发过程。它提供了一种快速构建可运行的应用程序的方式,内置了Tomcat服务器和默认配置,使得开发者无需过多关注配置细节...
- **定义**:Groovy是一种面向对象的编程语言,它直接运行在Java平台上,并且能够与现有的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