• 180807-Quick-Task 动态脚本支持框架之Groovy脚本加载执行


    logo

    Quick-Task 动态脚本支持框架之Groovy脚本加载执行

    上一篇简答说了如何判断有任务动态添加、删除或更新,归于一点就是监听文件的变化,判断目录下的Groovy文件是否有新增删除和改变,从而判定是否有任务的变更;

    接下来的问题就比较明显了,当任务变更之后,就需要重新加载任务了,即如何动态的编译并执行Groovy文件呢?

    相关系列博文:

    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对象之后,借助反射来创建对象

    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. 一灰灰Bloghttps://liuyueyi.github.io/hexblog

    一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛

    2. 声明

    尽信书则不如,已上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激

    3. 扫描关注

    小灰灰Blog&公众号

    QrCode

    知识星球

    zhishi

  • 相关阅读:
    [置顶] 新修改ADB,支持Android 4.2 系统 ,全部中文命令,手机屏幕截图等等
    归并排序
    Sciter/HTMLayout内存占用评测
    ASP.NET面试题总结
    uva 1356 Bridge ( 辛普森积分 )
    在没备份undo的情况下,undo丢失,重启数据库报ORA-01157错误
    以天徒龙记
    struts-config.xml 文件:
    struts.xml文件:
    web.xml文件:
  • 原文地址:https://www.cnblogs.com/yihuihui/p/9439862.html
Copyright © 2020-2023  润新知