Groovy與Java程式碼間的互操作
1Groovy互操作說明
Groovy指令碼有兩種呼叫方式,一是作為普通指令碼檔案(.groovy),使用Groovy提供的命令列groovy或者通過類groovy.lang.GroovyShell來呼叫。二是作為普通的Java類檔案(.class),用傳統的方式來呼叫,這需要先使用groovyc把指令碼檔案編譯成類檔案,然後再使用java命令來呼叫。
2Groovy指令碼呼叫Groovy指令碼
2.1程式碼:
Test.groovy:
package org.nick;
class Test{
Test(){
t = new TestS();
t.a();
}
static
t = new Test();
}
}
TestS.groovy:
package org.nick;
class TestS{
void a(){
println("Hello World");
}
}
2.2使用groovy命令:
i.說明:不可行。由於groovy沒有提供指定classpath的引數,因此,當兩個groovy指令碼需要進行互相呼叫時,Test.groovy將不能找到他所需要的TestS.groovy的定義,因此,通過groovy命令,不能實現兩個指令碼間的直接呼叫。
2.3使用GroovyShell
i.說明:可行。由於GroovyShell是一標準的Java類,因此,我們可以通過指定classpath,來找到所需的類。但這裡有一個前提,被呼叫的指令碼需要事先編譯為.class檔案。
ii.例項:
<target name="run" depends="init">
<java classname="groovy.lang.GroovyShell">
<classpath refid="run.path"/>
<arg value="${src.dir}/org/nick/Test.groovy" />
</java>
</target>
注:classpath當中包含了GroovyShell所在的jar,和被呼叫指令碼編譯後類檔案的目錄。
2.4使用java命令:
i.說明:可行。由於所有的指令碼檔案都被編譯為了.class檔案,因此,我們可以像一般的情況那樣,在指令碼之間互相呼叫。
ii.例項:
<java classname="org.nick.Test">
<classpath refid="run.path"/>
</java>
3Groovy指令碼呼叫Java程式碼
3.1程式碼:
Test.groovy:
package org.nick;
class Test{
Test(){
b = new TestJ();
b.a();
}
staticvoid main(String[] args){
t = new Test();
}
}
TestJ.java:
package org.nick;
public class TestJ {
public void a(){
System.out.println("Hello");
}
}
3.2使用groovy命令:
i.說明:理論不可行。原因同上,由於groovy不能指定其他類所在的位置,所以理論上不可行。但實際上groovy指令碼內部是能夠呼叫java.*等包中的Java類的,也就是說只要我們把我們自己寫的Java類提前編譯了,並放到classpath所指定的位置,我們就能使用groovy命令來實現Groovy指令碼呼叫Java程式碼。
3.3使用GroovyShell:
i.說明:可行。理由同上。只要把Java檔案提前編譯了即可。
3.4使用java命令:
i.說明:可行。理由同上。
4Java程式碼呼叫Groovy指令碼
4.1程式碼:
Groovy指令碼:
package org.nick;
for(it in args)
println(it)
Groovy類:
package org.nick;
class Test{
void a(name){
println("Hello ${name}");
}
}
4.2使用GroovyShell呼叫Groovy指令碼:
i.說明:通過GroovyShell類,我們可以在Java程式程式碼中直接載入和執行Groovy指令碼。而且,通過Binding類,我們還可以向Groovy指令碼傳遞引數的值。
ii.程式碼:
package org.nick;
public class GroovyTest {
public static void main(String[] args) throws Exception{
Binding binding = new Binding();
binding.setVariable("args", new String[]{"aaa","bbb","ccc"});
GroovyShell shell = new GroovyShell(binding);
Object obj = shell.evaluate(new File("src/org/nick/Test.groovy"));
}
}
4.3使用GroovyScriptEngine呼叫Groovy指令碼:
i.說明:GroovyScriptEngine是比GroovyShell更完整的一個方案,通過roots變數,我們指定了指令碼檔案所在的目錄,然後在需要執行時,GroovyScriptEngine將根據roots中的變數查詢並執行指定的指令碼檔案。同樣,我們可以通過Binding類為指令碼傳入引數。另外,有一點很重要的就是,當我們所呼叫的指令碼呼叫了另一指令碼時,如果使用GroovyShell方式且被呼叫指令碼未編譯為Java類,那麼將出現ClassNotFound錯誤,但如果使用GroovyScriptEngine,那麼當一指令碼呼叫另一指令碼時,即使另一指令碼未編譯為Java類,但只要他出現在roots變數所指向的位置,GroovyScriptEngine也能找到該對應的指令碼。
ii.程式碼:
package org.nick;
public class GroovyTest {
public static void main(String[] args) throws Exception {
String[] roots = new String[] { "src/org/nick" };
GroovyScriptEngine gse = new GroovyScriptEngine(roots);
Binding binding = new Binding();
binding.setVariable("args", new String[] { "aaa", "bbb", "ccc" });
gse.run("Test.groovy", binding);
}
}
4.4使用GroovyClassLoader載入Groovy類:
i.說明:通過GroovyClassLoader我們可以像在Java程式碼當中那樣,動態載入由Groovy指令碼書寫的類。並且通過對所裝載的類進行例項化,我們可以以一種類似於反射的方式來呼叫其內部的方法。
ii.程式碼:
package org.nick;
public class GroovyTest {
public GroovyTest() {
try {
ClassLoader parent = getClass().getClassLoader();
GroovyClassLoader loader = new GroovyClassLoader(parent);
Class groovyClass = loader.parseClass(new File
("src/org/nick/Test.groovy"));
GroovyObject groovyObject = (GroovyObject)
groovyClass.newInstance();
groovyObject.invokeMethod("a",new Object[]{"aaa"});
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
GroovyTest t = new GroovyTest();
}
}