jvm運行groovy類有兩種方式:
1.使用groovyc編譯所有的*.groovy為java的*.class文件,把這些*.class文件放在java類路徑中,通過java類加載器來加載這些類。
2.通過groovy的類加載器在運行時直接加載*.groovy文件並且生成對象,在這種方式下,沒有生成任何*.class,但是生成了一個java.lang.Class對象的實例,也就是說,當groovy代碼中包括一個new MyClass()的表達式時,並且也有一個MyClass.groovy的文件,這個文件將被解釋,一個MyClass的類型將被產生並且增加到類加載器中,在代碼中將像從*.class一樣獲取到MyClass對象。
沒有生成.class文件也可以用生成class對象的實例?
沒錯,實際上只要有符合虛擬機規范的二進制字節流被解析成方法區的數據結構就可以生成class對象,具體可以看一下類的加載過程。
https://blog.csdn.net/iteye_7617/article/details/82474191
https://www.cnblogs.com/amosli/p/3970810.html
groovy基本語法:
https://www.cnblogs.com/amosli/p/3970810.html
引入方式:
https://www.jianshu.com/p/e8dec95c4326
1.GroovyClassLoader:運行時加載groovy代碼,生成.class對象
GroovyClassLoader groovyClassLoader = new GroovyClassLoader(); String scriptText = "class Hello { void hello() { println 'hello' } }"; //將Groovy腳本解析為Class對象 Class clazz = groovyClassLoader.parseClass(scriptText); //Class clazz = groovyClassLoader.parseClass(new File("script.groovy")); assertEquals(clazz.getName(),"Hello"); clazz.getMethod("hello").invoke(clazz.newInstance());
2.GroovyScriptEngine:運行時加載腳本,並監聽腳本變化,當腳本發生變化時重新加載,這個厲害了啊
groovy.util.GroovyScriptEngine 類為 GroovyClassLoader 其上再增添一個能夠處理腳本依賴及重新加載的功能層, GroovyScriptEngine可以從指定的位置(文件系統,URL,數據庫,等等)加載Groovy腳本
可以使用一個CLASSPATH集合(url或者路徑名稱)初始化GroovyScriptEngine,之后便可以讓它根據要求去執行這些路徑中的Groovy腳本了.GroovyScriptEngine同樣可以跟蹤相互依賴的腳本,如果其中一個被依賴的腳本發生變更,則整個腳本樹都會被重新編譯和加載。
//script/groovy/hello.groovy println "hello $name"
GroovyScriptEngine scriptEngine = new GroovyScriptEngine("script/groovy"); Binding binding = new Binding(); binding.setVariable("name", "groovy"); while (true){ scriptEngine.run("hello.groovy", binding); TimeUnit.SECONDS.sleep(1); }
3.GroovyShell:這種看起來不是很實用...
GroovyShell shell = new GroovyShell(); //可以綁定更多變量 shell.setVariable("age",22); //直接求值 shell.evaluate("if(age < 18){'未成年'}else{'成年'}"); //解析為腳本,延遲執行或者緩存起來 Script script = shell.parse("if(age < 18){'未成年'}else{'成年'}"); assertEquals(script.run(), "成年"); //可以從更多位置加載/執行腳本 //shell.evaluate(new File("script.groovy")); //shell.evaluate(new URI("http://wwww.a.com/script.groovy"));
還可以這樣:
GroovyShell shell = new GroovyShell(); Script scrpt = shell.parse("script.groovy"); Binding binding = new Binding(); binding.setVariable("str1", "value1"); binding.setVariable("str2", "value2"); scrpt.setBinding(binding); System.out.println(scrpt.evaluate("customConcat(str1, str2)")); script.groovy: def customConcat(def str1, def str2) { str1.concat(str2) }
4.Eval:這種是對GroovyShell的封裝
Binding binding = new Binding();
GroovyShell shell = new GroovyShell(binding);
Script scrpt = shell.parse("script.groovy");
binding.setVariable("str1", "value1");
binding.setVariable("str2", "value2");
binding.setVariable("newConcat", scrpt);
System.out.println(scrpt.evaluate("newConcat.customConcat(str1, str2)"));
metaClass:
運行期添加靜態方法和普通方法
https://blog.csdn.net/walkcode/article/details/24587457
groovy代碼和class文件的對應關系:
https://blog.csdn.net/jiangqian6481/article/details/83717442
1.對於沒有任何類定義
如果Groovy腳本文件里只有執行代碼,沒有定義任何類(class),則編譯器會生成一個Script的子類,類名和腳本文件的文件名一樣,而腳本的代碼會被包含在一個名為run的方法中,同時還會生成一個main方法,作為整個腳本的入口。
2.對於僅有一個類
如果Groovy腳本文件里僅含有一個類,而這個類的名字又和腳本文件的名字一致,這種情況下就和Java是一樣的,即生成與所定義的類一致的class文件, Groovy類都會實現groovy.lang.GroovyObject接口。
3.對於多個類
如果Groovy腳本文件含有一個或多個類,groovy編譯器會很樂意地為每個類生成一個對應的class文件。如果想直接執行這個腳本,則腳本里的第一個類必須有一個static的main方法。
4.對於有定義類的腳本
如果Groovy腳本文件有執行代碼, 並且有定義類, 那么所定義的類會生成對應的class文件, 同時, 腳本本身也會被編譯成一個Script的子類,類名和腳本文件的文件名一樣
如何使用groovyc 和 groovy:
