使用GroovyShell作为“表达式计算器/引擎”(或:如何重用GroovyShell)

时间:2011-03-16 09:16:28

标签: groovy groovyshell

我在程序中使用GroovyShell作为“表达式评估程序/引擎”。它接受两个输入:(a)一个或多个init脚本(b)用户定义的脚本。然后两者在运行时连接成大块脚本(文本)并提供给shell。

String initScripts = getFromDB()
String userScript = getFromUser()

def shell = new GroovyShell()
output = shell.evaluate(initScripts + userScript)

上面的代码将在循环中运行,其中userScript的内容会有所不同。

到目前为止,initScripts仅包含可能在def $yyyy = new Date().format('yyyy')中引用的变量定义(例如userScript)(例如print "$yyyy 001")。

有没有更有效的方法呢? (例如,重用shell,怎么样?)因为现在它非常慢。

编辑:Groovy是必须的。请不要推荐其他脚本引擎。

编辑:我在想GroovyShell是否可以这样做(伪代码):

def shell = new GroovyShell()
shell.evaluate(initScripts)

for each userScript in DB {
    shell.put(userScript )
    def result = shell.evaluateThat()
    println "Result is $result"
}

这可能吗? (上次我用谷歌搜索它是不可能的,但我希望我错了)

3 个答案:

答案 0 :(得分:7)

您可以缓存GroovyShell,您无需始终创建新的

final static GroovyShell shell = new GroovyShell()

此外,如果您多次运行一个脚本,也可以缓存它们。您可以使用GroovyShell.parse(String scriptText)创建Script,使用Script.run()运行该脚本。

This section文档也可能有所帮助,您也可以动态创建groovy对象而不是脚本。

答案 1 :(得分:1)

我想你可以避免每次都建立一个完整的groovy环境的重量。

从Java 6开始,Java中有一个脚本API支持,允许您使用轻量级脚本引擎。

作为示例,请参阅this page in groovy website,了解如何使用GroovyScriptEngineImpl在Java应用程序中启动groovy脚本。

注意你可能会失去一些时髦的善意,比如Groovy葡萄,但你能够

  • 重用您的脚本引擎
  • 确保您的脚本在应用程序上下文中出现(最终受益于Java对象的使用)

编辑需要注意的一点是,GroovyScriptEngineImplGroovyShell都不能保证任何线程的安全性,因为任何groovy脚本都可以自由地生成任意数量的线。实际上,保证线程安全的唯一方法是installing a SecurityManager禁止线程操作。实际上,即使这样也不能保证线程安全(因为只有通过确保所有Java代码库都是线程安全的才能实现此线程安全性。)

答案 2 :(得分:0)

我最终这样做了:

def shell = new GroovyShell()
shell.evaluate(initScripts)

for( i in 1..count )
{
    output = shell.evaluate(userScripts);
}

为了安全起见,您可以将shell放入ThreadLocal或池中。