前言:請各大網友尊重本人原創知識分享,謹記本人部落格:南國以南i
簡介:
Groovy是用於Java虛擬機器的一種敏捷的動態語言,它是一種成熟的物件導向程式語言,既可以用於物件導向程式設計,又可以用作純粹的指令碼語言。使用該種語言不必編寫過多的程式碼,同時又具有閉包和動態語言中的其他特性。
Groovy特性:
可將java程式碼在Groovy指令碼動態編碼、程式碼被修改達到不重啟服務的目的(類似於熱部署)
核心涉及:
ClassLoader:就是類的裝載器,它使JVM可以動態的載入Java類,JVM並不需要知道從什麼地方(本地檔案、網路等)載入Java類,這些都由ClassLoader完成。
GroovyClassLoader:動態地載入一個指令碼並執行它的行為。GroovyClassLoader是一個定製的類裝載器,負責解釋載入Java類中用到的Groovy類。
Java與Groovy轉換
第一步:引入Groovy依賴
<!--Groovy指令碼依賴--> <dependency> <groupId>org.codehaus.groovy</groupId> <artifactId>groovy</artifactId> <version>2.5.14</version> </dependency>
第二步:建立interface介面宣告方法
public interface CallAnalysis { default void load() { } }
第三步:在resources目錄下建立.groovy檔案
package groovy import com.example.groovy.testgroovy.task.CallAnalysis import groovy.util.logging.Slf4j @Slf4j class CallAnalysisImpl implements CallAnalysis{ @Override void load() { log.info("我被Groovy指令碼載入...") } }
第四步:建立Groovy指令碼裝載類,動態解析指令碼為Class
package com.example.groovy.testgroovy.task; import groovy.lang.GroovyClassLoader; public class GroovyUtils { private final static ClassLoader classLoader = GroovyUtils.class.getClassLoader();//獲取當前類裝載器 //ClassLoader:就是類的裝載器,它使JVM可以動態的載入Java類,JVM並不需要知道從什麼地方(本地檔案、網路等)載入Java類,這些都由ClassLoader完成。 public final static GroovyClassLoader groovyClassLoader = new GroovyClassLoader(classLoader); //GroovyClassLoader:負責在執行時編譯groovy原始碼為Class的工作,從而使Groovy實現了將groovy原始碼動態載入為Class的功能。 /** * . * 獲取例項化物件 * @param script groovy指令碼內容 * @param <T> * @return * @throws IllegalAccessException * @throws InstantiationException */ public static <T> T instanceTaskGroovyScript(String script) throws IllegalAccessException, InstantiationException { Class taskClz = groovyClassLoader.parseClass(script); T instance = (T) taskClz.newInstance(); return instance; } }
第五步:讀取指令碼內容,執行指令碼
package com.example.groovy.testgroovy.task; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.FileUtils; import org.springframework.stereotype.Component; import java.io.File; import java.io.IOException; @Slf4j @Component public class CallAnalysisGroovyTask { /** * . * 讀取指令碼內容 * * @return */ public static String getGroovy() { String context = ""; try { String path = "E:\\IDEAFile\\testgroovy\\src\\main\\resources\\groovy\\CallAnalysisImpl.groovy"; context = FileUtils.readFileToString(new File(path));//將指令碼內容轉為字串 } catch (IOException e) { log.error("file is not found[{}]", e); } return context; } /** * . * 執行groovy指令碼 * * @param script */ public static void execGroovy(String script) { try { CallAnalysis objClass = GroovyUtils.instanceTaskGroovyScript(script);//獲取例項物件 objClass.load();//呼叫指令碼方法 } catch (Exception t) { log.error("execGroovy file {} error", script); } } /** * . * main方法 * @param args */ public static void main(String[] args) { System.out.println("=================="); CallAnalysisGroovyTask task = new CallAnalysisGroovyTask(); String script = task.getGroovy();//獲取指令碼 execGroovy(script);//例項化指令碼,執行方法 System.out.println("=================="); } }
Groovy特性驗證
利用Groovy指令碼特性,不重啟服務,實時修改資料
第一步:將之前Groovy指令碼資料修改。存於資料庫表中,動態載入指令碼
@Slf4j class CallAnalysisImpl implements CallAnalysis { private int anInt = 10; private int bnInt = 10; @Override void load() { log.info("當前類:[{}]", this.getClass().getName()) log.info("我被Groovy指令碼載入...") log.info("計算結果:[{}]", (anInt + bnInt)) } }
第二步:資料庫表中:新增、查詢Groovy指令碼,動態載入執行
/** * . * 讀取指令碼,進行入庫操作 * * @return */ @GetMapping("/saveScript") public String saveScript() { String scriptStr = callAnalysisGroovyTask.getGroovy(); Script script = new Script();//實體類物件 script.setScript(scriptStr);//指令碼內容 script.setRuleId("1");//規則id script.setScriptName("演示一");//指令碼名稱 service.save(script); return "新增成功"; } /** * . * 從資料庫表中,動態獲取指令碼 * * @param ruleId 規則id * @return 指令碼內容 */ @GetMapping("/groovy") public String groovy(final String ruleId) { Script scr = scriptService.findScriptByRuleId(ruleId);//根據規則id查詢 String scriptStr = scr.getScript(); callAnalysisGroovyTask.execGroovy(scriptStr); return scriptStr; }
新增結果
查詢結果、控制檯執行結果
第三步:多次修改表資料值,檢視執行結果
總語:
目的達成,可見在不重啟服務時,多次修改資料,指令碼內容都會被動態載入。此處只是簡單舉例驗證,可自行擴充套件