Using GroovyShell as "expression evaluator/engine" (or: How to reuse GroovyShell)
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 possib开发者_开发知识库le? (Last time I googled it's not possible, but I'm hoping I'm wrong)
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.
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).
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.
精彩评论