使用另一个groovy脚本中的groovy脚本

时间:2019-06-04 08:26:35

标签: java groovy classpath

我想在另一个groovy脚本中使用'Util'groovy脚本。我不想每次都在我的“主要” groovy脚本中加载“ Util”类。因此,使用evaluateGroovyShell不适合我的情况。

我的Java应用程序从数据库中获取“主要” groovy脚本主体,对其进行解析并每次都从“主要”脚本中调用test()方法。

java代码:

GroovyShell groovyShell = new GroovyShell();
Script parsedScript = groovyShell.parse(scriptBody);

ResultPojo result = (ResultPojo) parsedScript.invokeMethod("test", null);

“主要”脚本

public int test(){
    // this will not work at the moment
    int result = GroovyUtils.sum(); 
    return result;
}

“ Util”类也将位于数据库中。 “ Util”类将以某种方式在应用程序启动时加载,并且每隔X分钟就会重新加载。

class GroovyUtils{

    static int sum() {
        return 2+1;
    }
}

就像我说的那样,我不想在“ main”脚本中“解析” GroovyUtils类,因为这很费时间。

理想情况下,我想在需要时导入GroovyUtils脚本。

import groovy.GroovyUtils;

public int test(){
    int result = GroovyUtils.sum(); 
    return result;
}

但是为了导入脚本,需要将脚本保存在Java应用程序运行的同一文件夹中。 Java应用程序以.war格式部署在远程应用程序服务器上。

我能以某种方式动态地将GroovyUtils加载到CLASSPATH而不保存它,以便从“主”脚本中导入它吗?

有什么建议吗?我主要关心的是速度和可重装性。

1 个答案:

答案 0 :(得分:1)

如果您想通过数据库创建传递过程,则可以通过扩展GroovyClassLoader并实现公共类loadClass(name, lookupScriptFiles, preferClassOverScript, resolve)方法来实现,该方法将在数据库的某些表中进行搜索。

让我简化您的目标并排除数据库。

classloaders是一种标准行为:在类路径中搜索并加载类

GroovyClassLoader允许在运行时向类路径添加新路径,因此它将在指定的文件夹或jar文件中另外搜索类。

classloader将已解析的类保留在内存中,并且groovy classloader提供了受保护的方法来按名称删除类定义:removeClassCacheEntry(java.lang.String)

最后一个例子:

/myprj/classes/util/MyClass.groovy

package util
class MyClass{
    def echo(msg){ println msg }
}

运行主脚本的代码

//create shell and init classloader just once
GroovyShell gs = new GroovyShell()
gs.getClassLoader().addClasspath("/myprj/classes/")

//forces classloader to recompile on file change
//this is alternative to removeClassCacheEntry
//but in some specific cases this reload will not work
gs.getClassLoader().setShouldRecompile​(true)

Script script = gs.parse('''
  import util.MyClass
  new MyClass().echo("hello world")
''')

script.run() // prints 'hello world'

//removeClassCacheEntry is alternative to setShouldRecompile​
//you can use it to remove compiled class from this classloader
println gs.getClassLoader().getLoadedClasses() // outputs util.MyClass, and Script1
gs.getClassLoader().removeClassCacheEntry("util.MyClass")
println gs.getClassLoader().getLoadedClasses() // outputs Script1

返回数据库:您可能有一个守护程序线程,该线程扫描数据库中常见的代码更改并将修改后的源导出到定义为其他类路径的文件夹中,并为类加载器触发removeClassCacheEntry。因此,对已删除类的下一次访问将强制由GroovyClassLoader对其进行解析。

  

注意:通过使用动态类加载,您可能会遇到以下情况:同一类的两个版本存在于内存中,并且它们将无法相互比较和分配。因此,您可能会遇到以下错误:could not assign MyClass to MyClass