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

使用GroovyShell作为;表达式计算器/引擎“;(或:如何重用GroovyShell),groovy,groovyshell,Groovy,Groovyshell,我在程序中使用GroovyShell作为“表达式计算器/引擎”。它接受两个输入:(a)一个或多个初始化脚本(b)用户定义的脚本。然后在运行时将这两个脚本连接为一大块脚本(文本)并馈送到shell String initScripts = getFromDB() String userScript = getFromUser() def shell = new GroovyShell() output = shell.evaluate(initScripts + userScript) 上述代

我在程序中使用
GroovyShell
作为“表达式计算器/引擎”。它接受两个输入:(a)一个或多个初始化脚本(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“$yyyyy 001”

有没有更有效的方法?(例如,如何重用外壳?)

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

编辑:我正在考虑GroovyShell是否可以做到这一点(伪代码):


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

我想你可以避免每次构建一个完整的groovy环境的负担

自Java6以来,Java中就有一个脚本API支持,它允许您使用轻量级脚本引擎

作为示例,请参见解释如何使用在Java应用程序中启动groovy脚本

请注意,你可能会失去一些美味佳肴,比如美味葡萄,但你可以做到

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

EDIT需要注意的一件重要事情是,无论是
GroovyScriptEngineImpl
还是
GroovyShell
都不能保证任何类型的线程安全,因为任何groovy脚本都可以自由生成任意数量的线程。事实上,确保线程安全的唯一方法是禁止线程操作。事实上,即使这样也不能保证线程安全(因为只有确保所有Java代码库都是线程安全的,才能实现线程安全)。

您可以缓存GroovyShell,您不必总是创建一个新的:

final static GroovyShell shell = new GroovyShell()
此外,如果您多次运行一个脚本,也可能会缓存它们。您可以使用创建
脚本
,用于运行脚本

这些文档的一部分也可能有帮助,您还可以动态创建groovy对象,而不必使用脚本。

我最终会这样做:

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

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

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

GroovyShell是无状态且线程安全的吗?有些人可以使用不同的脚本同时使用程序(这是肯定的,因为
userScript
可能每个用户,甚至每个调用都不同)。是的,它是线程安全的,无状态的(但我看到,如果不使用默认构造函数,它不会创建防御副本-在您的情况下,这不应该是一个问题)我认为您可以重用shell对象,但我不认为您可以重用script对象。脚本实例使用
Map
进行绑定,这不是线程安全的。我认为GroovyShell是线程安全的,因为它使用
binding
对象作为可以更改的构造函数。我已经研究了它,但我的问题仍然是,它是线程安全的吗?我如何重复使用它?(如果我要使用GroovyScriptEngineImpl),很抱歉,我看不出你的问题中有什么是关于线程安全的。糟糕,我没有明确地说:P
def shell = new GroovyShell()
shell.evaluate(initScripts)

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