我有一个在Tomcat中运行的Java Spring应用程序,用于根据传入的文件执行各种处理规则。由于文件类型和规则发生了变化,我想使用Groovy动态加载新的/更改的功能,而不必每次都重新编译/重新启动Java应用程序。
从Groovy documentation开始“在Java中动态加载并运行Groovy代码”,
GroovyClassLoader gcl = new GroovyClassLoader();
Class clazz = gcl.parseClass(myStringwithGroovyClassSource, "SomeName.groovy");
Object aScript = clazz.newInstance();
MyInterface myObject = (MyInterface) aScript;
myObject.interfaceMethod();
我创建了我的SomeName.groovy版本,它实现了MyInterface并修改了我的Java应用程序,然后创建了该类的实例,如上所示。我知道正在正确读取我的Groovy文件,因为如果我打印出myObject.getClass()。toString,它会显示SomeName.groovy中定义的正确对象类型;但是,当它调用其中一个实现的方法(myObject.interfaceMethod())时,它什么都不做。
我已经在Tomcat之外的Java应用程序中测试了这种方法,但它确实有效,所以我不确定为什么在app服务器内运行它会导致它崩溃。另外,我已经确认groovy-all-2.1.8.jar包含在我的项目中。
提前感谢您提供的任何信息,这些信息可能会说明动态加载可能失败的原因。
THX。
答案 0 :(得分:3)
您正在使用的parseClass()
方法的形式根本不会查看任何外部文件。相反,它会处理第一个String
参数(在您的情况下为myStringwithGroovyClassSource
),就好像它是Groovy源文件的文本内容,以及第二个String
参数(在您的情况下为文字"SomeName.groovy"
),就像它是该文件的名称一样。此方法根本不会打开或解析任何 ACTUAL 文件。
要使此代码正常工作,您必须预定义变量myStringwithGroovyClassSource
。整体效果看起来像这样:
def myStringwithGroovyClassSource = """
class SomeName implements MyInterface {
def prop1 = 1, prop2 = 2
def interfaceMethod() { println prop1 }
}
"""
interface MyInterface { def interfaceMethod() }
GroovyClassLoader gcl = new GroovyClassLoader()
Class clazz = gcl.parseClass(myStringwithGroovyClassSource, "SomeName.groovy")
Object aScript = clazz.newInstance()
MyInterface myObject = (MyInterface) aScript
myObject.interfaceMethod()
现在,另一方面,正如您所说,如果您已经有一个名为SomeFile.groovy
的外部未编译的Groovy源文件,您希望通过GroovyClassLoader将其带入您的脚本,那么您需要更改现有的代码如下:
interface MyInterface { def interfaceMethod() }
GroovyClassLoader gcl = new GroovyClassLoader()
Class clazz = gcl.parseClass("SomeName.groovy" as File)
Object aScript = clazz.newInstance()
MyInterface myObject = (MyInterface) aScript
myObject.interfaceMethod()
如果文件中的代码在编译时是有效的,那么你应该没有问题。