Using GroovyShell as “expression evaluator/engine” (or: How to reuse GroovyShell)

≯℡__Kan透↙ 提交于 2021-01-27 02:55:26

问题


I'm using GroovyShell as an "expression evaluator/engine" inside my program. It accepts two inputs: (a) one or more init scripts (b) user-defined script. Both are then concatenated at runtime as big chunk of script (text) and feed to the shell.

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

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

The above code will run in a loop, where the contents of userScript will vary.

So far, initScripts only contain variable definitions (e.g. def $yyyy = new Date().format('yyyy')) which might be referenced in userScript (e.g. print "$yyyy 001").

Is there any more efficient approach for this? (E.g. reusing the shell, how?) Because right now it's very slow.

Edit: Groovy is a must. Please don't recommend other scripting engine.

Edit: I'm thinking whether GroovyShell can do this (pseudo-code):

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

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

Is this possible? (Last time I googled it's not possible, but I'm hoping I'm wrong)


回答1:


You can cache the GroovyShell, you don't need to create a new one always:

final static GroovyShell shell = new GroovyShell()

Also if you run one Script many times you may cache them too. You can create a Script with GroovyShell.parse(String scriptText), use Script.run() to run the script.

This section of the documentation might help too, instead of scripts you can also create groovy objects dynamically.




回答2:


I guess you could avoid the weight of building a full groovy environment each time.

Since Java 6, there is a scripting API support in Java, which allows you to use lightweight scripting engines.

As an example, see this page in groovy website explaining how to start a groovy script in a Java application using GroovyScriptEngineImpl.

notice you may loose some groovy goodnesses, like maybe Groovy grape, but you'll be able to

  • reuse your script engine
  • ensure your script evals in application context (eventually benefitting from Java objects usage)

EDIT one important thing to notice is that neither GroovyScriptEngineImpl nor GroovyShell can guarantee you any kind of thread safety, as any groovy script is free to spawn any number of thread. In fact, the only way you could guarantte thread safety would be by installing a SecurityManager forbidding thread operations. In fact, even that wouldn't guarantee thread safety (as this thread safety could only be achieved by ensuring all your Java code base is thread safe).




回答3:


I end up doing this:

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

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

And just to be safe, you can put shell in ThreadLocal or pool.



来源:https://stackoverflow.com/questions/5323114/using-groovyshell-as-expression-evaluator-engine-or-how-to-reuse-groovyshell

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!