180807-Quick-Task 動態腳本支持框架之Groovy腳本加載執行

logo

Quick-Task 動態腳本支持框架之Groovy腳本加載執行

上一篇簡答說了如何判斷有任務動態添加、刪除或更新,歸於一點就是監聽文件的變化,判斷目錄下的Groovy文件是否有新增刪除和改變,從而斷定是否有任務的變動;java

接下來的問題就比較明顯了,當任務變動以後,就須要從新加載任務了,即如何動態的編譯並執行Groovy文件呢?git

相關係列博文:github

I. Groovy文件動態加載

要想動態加載類,能夠怎麼辦?若是對JVM有必定了解的朋友可能知道,自定義一個ClassLoader,能夠實現從文件/網絡/DB/Jar包中讀取class文件,而Groovy,動態語言,簡單來講就是.groovy文件能夠直接運行,那麼咱們編碼中要怎麼玩?網絡

1. 依賴

讓我本身來實現Groovy文件的編譯執行,目前基本上是看不到啥但願的,因此果斷的藉助第三方工具類加載Groovy文件框架

pom文件添加依賴工具

<dependency>
    <groupId>org.codehaus.groovy</groupId>
    <artifactId>groovy-all</artifactId>
    <version>2.4.3</version>
</dependency>

2. 加載Groovy

直接利用上面jar包中提供的GroovyCalssLoader來加載Groovy文件便可,使用也比較簡單學習

@Slf4j
public class GroovyCompile {

    @SuppressWarnings("unchecked")
    public static <T> T compile(File codeSource, Class<T> interfaceType, ClassLoader classLoader)
            throws CompileTaskScriptException {
        try {
            GroovyClassLoader loader = new GroovyClassLoader(classLoader);
            Class clz = loader.parseClass(codeSource);

            // 接口校驗
            if (!interfaceType.isAssignableFrom(clz)) {
                throw new CompileTaskScriptException("illegal script type!");
            }

            return (T) clz.newInstance();
        } catch (IOException e) {
            log.error("load code from {} error! e: {}", codeSource, e);
            throw new CompileTaskScriptException("load code from " + codeSource + " error!");
        } catch (CompileTaskScriptException e) {
            throw e;
        } catch (Exception e) {
            log.error("initial script error! codePath: {}, e: {}", codeSource, e);
            throw new CompileTaskScriptException(
                    "initial script error! clz: " + codeSource + " msg: " + e.getMessage());
        }
    }
}

上面看着挺多,關鍵地方就三行,編譯爲class對象以後,藉助反射來建立對象ui

GroovyClassLoader loader = new GroovyClassLoader(classLoader);
Class clz = loader.parseClass(codeSource);
return (T) clz.newInstance();

另外還有一行,也能夠順帶湊一眼,判斷一個class是否爲另外一個class的子類,用的是編碼

interfaceType.isAssignableFrom(clz)

而判斷某個對象是否爲某類的子類用的則是 instance of設計

3. 調用包裝

上面既然提供了一個工具類,那麼接上篇的獲取變更文件以後,獲取File對象,藉此拿到任務對象,就比較清晰了

@Slf4j
public class ScriptLoadUtil {

    public static ITask loadScript(File file) {
        try {
            return GroovyCompile.compile(file, ITask.class, ScriptLoadUtil.class.getClassLoader());
        } catch (CompileTaskScriptException e) {
            log.error("un-expect error! e: {}", e);
            return null;
        }
    }
}

4. 小結

本篇內容比較簡單,知識點也沒多少,一個是利用GroovyClassLoader來編譯Groovy文件並獲取實例;另外一個就是如何判斷一個class是否爲另外一個class的子類

還有一個隱藏的點上面沒有說,那就是上面的GroovyCompile文件中,每次加載Groovy文件時,都是新建立了一個GroovyClassLoader,並由它來加載並實例Groovy任務,那麼問題來了

  • 可否用一個GoorvyClassLoader來管理全部的Groovy任務呢?
  • 上面的代碼實現中,不一樣的Groovy任務之間,能夠相互通訊麼?

針對上面的問題,暫不給出答案,後面再說

II. 其餘

0. 相關

博文:

項目:

1. 一灰灰Blog: https://liuyueyi.github.io/hexblog

一灰灰的我的博客,記錄全部學習和工做中的博文,歡迎你們前去逛逛

2. 聲明

盡信書則不如,已上內容,純屬一家之言,因我的能力有限,不免有疏漏和錯誤之處,如發現bug或者有更好的建議,歡迎批評指正,不吝感激

3. 掃描關注

小灰灰Blog&公衆號

QrCode

知識星球

zhishi

相關文章
相關標籤/搜索