使用grovyshell作为“表达评估器/发动机”(OR:如何重复使用grovyshell)
-
24-10-2019 - |
题
我在用着 GroovyShell
作为我程序内部的“表达评估器/引擎”。它接受两个输入:(a)一个或多个初始脚本(b)用户定义的脚本。然后,两者在运行时将两者串联成大块的脚本(文本),然后馈送到外壳。
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"
).
有什么更有效的方法吗? (例如,重用外壳,如何?),因为现在是 非常 减缓。
编辑: 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"
}
这可能吗? (上次我谷歌搜索不可能,但我希望我错了)
解决方案
您可以缓存Grovyshell,您无需始终创建一个新的:
final static GroovyShell shell = new GroovyShell()
另外,如果您多次运行一个脚本,也可以缓存它们。您可以创建一个 Script
和 groovyshell.parse(字符串scripttext), , 利用 script.run() 运行脚本。
本节 文档也可能会有所帮助,而不是脚本,您也可以动态创建Groovy对象。
其他提示
我想您可以避免每次建立一个完整的槽环境的重量。
自Java 6以来,Java中有脚本API支持,可让您使用轻质的脚本引擎。
例如,请参阅 此页面在Groovy网站上 解释如何使用Java应用程序启动Groovy脚本 GroovyScriptEngineImpl
.
请注意,您可能会失去一些令人讨厌的美感,例如Groovy Grape,但您将能够
- 重复使用脚本引擎
- 确保您的脚本在应用程序上下文中的流动(最终从Java对象使用中受益)
编辑 要注意的一件重要的事情是 GroovyScriptEngineImpl
也不 GroovyShell
可以保证您任何类型的线程安全性,因为任何Groovy脚本都可以免费产生任何数量的线程。实际上,您可以保证线程安全的唯一方法就是 安装安全管理器 禁止线程操作。实际上,即使这样,也不能保证线程安全性(因为只有通过确保所有Java代码基库都安全,才能实现此线程安全)。
我最终这样做:
def shell = new GroovyShell()
shell.evaluate(initScripts)
for( i in 1..count )
{
output = shell.evaluate(userScripts);
}
为了安全起见,你可以说 shell
在 ThreadLocal
或游泳池。